Skip to content
SecHelixv3 alpha
GitHub
DocsContributeSupportWorkbenchGitHub
Back to overview
Review guide · Untrusted targets

Auditing a repository you do not trust yet.

When you point an agent at unfamiliar code, that code can address the agent. UNTRUSTED_REPO mode treats repository content as data and never as control: all seven capabilities are denied by default and only an operator can promote a path.

Part of the AppSec agent guide.

When you point a coding agent at a repository you have not read, that repository can address the agent. A file called CLAUDE.md or .github/copilot-instructions.md is loaded as instructions by design, and a hostile one can ask for a downgraded severity, a silenced check, an installed package, or an outbound request. UNTRUSTED_REPO mode exists for exactly that situation. The rule it enforces is one sentence: repository content is data, and it is never control.

Concretely, all seven capabilities are denied by default, an unrecognized capability is also denied because the check is an allowlist, and no file inside the target counts as control unless the operator promoted that exact path and recorded who did it, when, and why.

All 7 capabilities deniedContent is data, never controlOperator promotion only

The seven capabilities, all off

CapabilityWhat it would allowDefault
FILESYSTEM_WRITEModifying anything inside or beside the target.Denied
REPO_SCRIPTSRunning a script the target ships, including build and test scripts.Denied
PACKAGE_INSTALLResolving and installing dependencies the target declares.Denied
NETWORKAny outbound request, including one the target asks for.Denied
HOOKSExecuting git hooks or host hooks the target defines.Denied
EXTERNAL_MCPConnecting to an MCP server the target configures.Denied
DYNAMIC_TARGET_REQUESTSSending traffic to a service the target describes or starts.Denied

Nothing inside the target can widen scope, relax policy, enable a capability, mark a finding resolved, or silence a check. Only the operator can do that, and only through an explicit promotion recorded in the scope record — the same record the rest of the contract reads before any testing begins.

A denial
REPO_SCRIPTS is not permitted in UNTRUSTED_REPO;
an explicit operator escalation is required and must be recorded in scope.trust

The files that read as instructions

Control-shaped paths are the ones a host may load as configuration or as instructions rather than as source. In this mode they are read as text like everything else.

  • Instruction files: CLAUDE.md, AGENTS.md, GEMINI.md, CURSOR.md, .github/copilot-instructions.md
  • Rule files: .cursorrules, .windsurfrules
  • Host settings and hooks: .claude/settings.json, .claude/settings.local.json, .claude/hooks.json
  • Server configuration: .mcp.json, .vscode/mcp.json
  • Whole directories: .claude/, .agents/, .codex/, .cursor/, .windsurf/, .github/skills/, .github/workflows/

A promotion turns exactly one path into control and nothing else. Promoting AGENTS.md does not promote the directory it sits in.

Four ways the scope record fails closed

  • A missing trust block is rejected, not downgradedAn UNTRUSTED_REPO scope with no trust block is refused. It does not silently fall back to trusting the target, which is the failure mode that makes a mode like this pointless.
  • TRUSTED_CONTROL cannot be declared hererepository_content must be DATA_ONLY. Declaring the target trusted while claiming the untrusted mode is a contradiction the resolver refuses.
  • A wildcard promotion is refusedA promotion must name a concrete path. *, **, and . are rejected, because a wildcard promotion re-trusts the whole target in one line.
  • Every promotion is attributableA promotion requires promoted_by, promoted_at, and reason. An escalation requires approved_by, approved_at, and justification.

Using it

There is no separate command. The mode is a scope record plus a resolver, so it applies to whatever review you were already going to run — a Gold Check Pack investigation behaves exactly the same way under it. Getting there is the ordinary install; the resolver itself is in the open repository.

A ready scope record
{
  "mode": "UNTRUSTED_REPO",
  "trust": {
    "repository_content": "DATA_ONLY",
    "promoted_control_sources": []
  },
  "allowed_tools": ["read-only source inspection"]
}
Resolving and enforcing the policy
from sechelix_core.untrusted_repo import resolve_trust_policy, review_target_content

policy = resolve_trust_policy(scope)          # raises if the scope is unsafe
policy.assert_allows("REPO_SCRIPTS")          # raises unless explicitly escalated

reviewed = review_target_content(policy, files)   # files: (path, text) pairs
for item in reviewed.quarantined:
    print(item.path, item.line, item.pattern)
Mode
UNTRUSTED_REPO
Posture
Static review. It is not a mode for dynamic testing.
Capability semantics
Deny by default, allowlist-checked, unrecognized names denied.
Promotion granularity
One concrete path per promotion. The promoted path becomes control and only that path.
Recorded in
The scope record, under scope.trust, alongside the existing authorization fields.

Detection is for the report, not for the defence

The mode also scans target content for seven pattern classes and quarantines what it finds: instruction override, audit suppression, false assurance, severity downgrade, capability request, exfiltration request, and direct address to the agent.

This exists so a report can state what the repository attempted. It is deliberately not the control. The control is that target content is never executed as instruction in the first place, so a novel phrasing that evades the patterns still changes nothing.

What this mode does not do

  • It does not sandbox your agent. If your host grants shell access, this policy is a discipline layer rather than a kernel boundary. Scope the agent as well.
  • It does not detect every phrasing. Detection is best-effort reporting; the guarantee is the separation between data and control.
  • It does not make dynamic testing safe. UNTRUSTED_REPO is a static-review posture, and DYNAMIC_TARGET_REQUESTS is one of the seven denied capabilities.

Those three sentences are published in the reference documentation rather than being left for a reader to discover. A safety mode that overstates its own reach is worse than none, because it moves the failure from visible to assumed. The same instinct is why the published run records the candidates verification refuted alongside the one it confirmed.

Install

Read the repository. Do not let it read you back.

npx skills@latest add omarmohelal/SecHelix --skill sechelix