Security
Syntic Code runs on your machine, reads your code, and can run commands. This page explains how it keeps that power in check: who decides what it may do, what stops a hostile repository or web page from steering it, and how your credentials are protected. It is written for security reviewers and administrators, but anyone curious about the safety model will find it useful.
The ideas behind it
Four rules shape every safety feature in Syntic Code:
- You decide. By default, anything that changes your machine or reaches the network asks first. Modes and rules let you trade prompts for speed, but the choice is always yours or your administrator’s.
- The opened folder is untrusted input. A repository you clone may have been written by anyone. Until you trust it, it cannot run code, add tools or change how Syntic Code behaves, and even after you trust it, it can never choose your credential, your API address, your shell or a prompt-free mode.
- Stricter always wins. A deny rule from any source is kept. Switches that turn features off cannot be turned back on by another file. Organization policy sits above everything a user or project sets.
- Fail closed. When a check cannot finish (a reviewer that does not answer, a policy file that does not parse, managed settings that cannot be loaded), the result is a question or a refusal, never a silent “yes”.
The permission engine
Every tool call the agent makes passes through one permission engine before it runs.
| Layer | What it does | Page |
|---|---|---|
| Permission modes | Set the baseline: ask for everything, allow edits, let a reviewer judge (auto), plan only, or skip prompts entirely. | Permission modes |
| Rules | allow, ask and deny patterns per tool, command, path, domain or MCP server. Deny always wins. | Permission rules |
| Final argument check | If a hook or the person changes a call while approving it, the changed version is judged again by the same rules. A deny on the final version always blocks. | Permission rules |
| Shell command checks | The whole command is scanned, not just its start. A command whose allowed prefix hides a substitution, a pipe into a shell, or a privilege change is put back to you. | Commands that reach outside |
| File safety | Edits need a fresh read of the file, writes stay inside your working folders, and paths that escape through a symlink are refused. | Permission rules |
| Sensitive files | Shell startup files, git config and .git/, .syntic/, .mcp.json, editor folders and other tools’ config always ask, even when edits are otherwise allowed. | Permission rules |
Bypass mode, which skips prompts, is never offered by accident. It is only reachable when the person asks for it at launch, and an administrator can remove it with permissions.disableBypassPermissionsMode.
Folder trust
The first time you start Syntic Code in a folder, it asks whether you trust it. Until you say yes, nothing project-scoped loads: no project settings, hooks, MCP servers, agents, skills or git integration. Non-interactive runs in an untrusted folder run in this restricted state and say so.
Even in a trusted folder, the project’s own files cannot:
- choose the credential (
apiKey) or the API address (apiBaseUrl), - choose the shell commands run in,
- start a session in bypass or auto mode,
- add
allowrules to auto mode, - act as organization policy (a
settings.policy.jsonin a project is ignored), - set security-sensitive environment variables through their
envblock.
.env files in the project or its parents are never loaded into Syntic Code’s own environment. Details are on Folder trust.
The shell sandbox
The shell sandbox runs each agent command inside the operating system’s own sandbox (Seatbelt on macOS, bubblewrap on Linux). A sandboxed command can write only where you allow, cannot see your credential folders, and reaches only the network hosts you approve. Secret-looking variables in your environment (cloud keys, registry tokens, passwords) are removed from sandboxed commands too.
The sandbox is off until you or your administrator turn it on. Administrators can lock its network and file lists to the policy’s own entries.
Protecting your credentials
| Protection | How |
|---|---|
| No long-lived keys from sign-in | Browser sign-in returns a short-lived access token and a refresh token. The CLI never creates a static API key for you. |
| Private storage | Credentials live in ~/.syntic/credentials.json, readable only by your user account. |
| Hidden from child processes | SYNTIC_API_KEY, SYNTIC_OAUTH_REFRESH_TOKEN and other sign-in variables are removed from the environment of every shell command, hook, MCP server, git call and helper Syntic Code starts. |
| Fixed destination | Your credential is only ever sent over HTTPS to Syntic’s own API hosts on the default port. Any other address, a look-alike host, plain http, or an address with embedded user details is refused, and redirects are not followed. |
| Organization pin | forceLoginOrgUUID stops a work machine from using a personal account. |
Safe helpers
Syntic Code runs some programs itself: git, a browser opener, a shell. A cloned repository could try to plant a fake version of one of these.
- Helper programs are looked up on a cleaned
PATHwith the current folder, relative entries and anything inside the project removed. If no safe copy is found, the call fails rather than falling back. - Git runs with every setting in a repository’s
.git/configthat could start a program switched off (hooks paths, pagers, editors, external diff and text conversion, credential helpers, fsmonitor), inheritedGIT_*variables removed, and no prompts. It does not run at all in an untrusted folder.
Prompt injection
Text the agent reads (a file in the repository, a web page, a tool result, an issue comment) can contain instructions meant to steer it. A model cannot always tell those apart from yours, so Syntic Code does not rely on the model to refuse them. Instead, the defences sit outside the model:
- The permission engine does not care why a call was made. A command planted in a README still needs to pass your rules and prompts like any other.
- Data-leaving actions are caught locally. In auto mode, commands that would upload files, copy to a remote host or put secret-looking values in a URL always reach you, whether or not the reviewer is available.
- The auto mode reviewer judges each consequential call with a separate model against a fixed safety policy, and it fails closed. See Configure auto mode.
- High-impact actions always ask in auto mode: deleting outside the project, privilege changes, publishing, pushing to a remote, infrastructure changes and more.
- Web pages are summarized separately. When the agent fetches a page with a question, a separate small model reads the page and answers the question, so the main conversation gets a summary rather than the page’s raw text.
- Project MCP servers need your approval before they first connect, and again if the repository changes their command.
None of these make prompt injection impossible. Review what the agent proposes, especially in folders you do not know.
MCP servers and plugins
MCP servers and plugins add code and tools that Syntic Code does not write. Treat them like any other dependency.
- Administrators can allow, block or provide MCP servers for everyone: Managed MCP servers.
- Plugins come from marketplaces, which administrators can restrict: Plugins for your organization and Plugin security.
- Every MCP tool can be denied by name with a permission rule (
mcp__<server>__<tool>).
Undo
Before the agent changes a file, Syntic Code keeps a copy. If something goes wrong, you can rewind file changes from the session. See Checkpointing.
Good practice
For everyone
- Keep the default mode in folders you do not know, and read prompts before you accept them.
- Add deny rules for secrets:
Read(.env),Read(*.pem),Read(~/.ssh/**). - Turn on the shell sandbox for long unattended runs.
- Do not paste credentials into prompts. Use
apiKeyHelperor environment variables for tools that need them.
For teams
- Deploy a managed policy with your deny rules,
disableBypassPermissionsMode, and an MCP allow list. - Keep everyone on a supported build with
minimumVersion. - Use
allowManagedPermissionRulesOnlywhere only reviewed allow rules should count. - Export usage events to your monitoring tools to spot unusual activity: Monitor usage.