Deepagents Cli
Threat Model
evidence-derived · Praxen 1.3.0 · graph contract 1.4 · built against deepagents-cli-findings-2026-08-12.json
25Components
38Flows
9Boundaries
16Confirmed
3Potential
2Partial
4Mitigated
Summary
The Agent (as modeled)

Deep Agents Code is a terminal coding assistant that a developer — or a CI workflow — points at a project directory and lets drive that project: it reads and rewrites files, runs shell commands, fetches web pages, delegates to sub-agents, and extends itself with operator-configured MCP servers. Its declared safety model rests on one control, a human approval prompt in front of every side-effecting tool. Two surfaces matter most. The first is the project directory itself: the runtime samples the working directory's Makefile and file listing into the system prompt on every turn, and tool results — fetched pages, search snippets, MCP responses, command output — come back into the conversation with nothing marking them as untrusted. The second is the run mode: the approval prompt is real and well built in the interactive terminal, and effectively absent in the headless and CI paths the same binary offers.

Priority Threats (led by attack paths)

The first thing to deal with is unattended execution. In a headless run every action other than a shell command is approved automatically, and there is no setting that puts approval back for file writes, deletes, web requests or sub-agent launches. The one control that does apply to shell commands is not a boundary: an allow-everything setting is accepted, and an ordinary allow-list is checked against the name of each command only, never its arguments — so allowing any interpreter or wrapper quietly allows everything. Put together with the untrusted content flowing into the prompt, a hostile repository can steer an unattended run into arbitrary commands on the developer's machine or the CI runner, and an attacker-controlled web page can get files rewritten. Fix the headless path first: give non-shell tools the same gate the terminal has, drop the allow-everything setting, and match commands on more than their first word.

Two further items deserve attention. The local agent-runtime server the front-end talks to runs with authentication switched off, so any other process running as the same user can read the conversation or inject instructions into it — and because sessions are checkpointed, those instructions come back when the thread resumes. That checkpoint database keeps everything the agent ever read, unencrypted, with no expiry, in a directory created without explicit permissions. Alongside these, an MCP server can currently exempt its own tools from approval by labelling them read-only, and nothing durable records what the agent did or decided — the audit stream exists but only fires for operators who have configured it, which makes any of the above hard to detect after the fact.

Architecture & Trust Boundaries
Attack paths are drawn in red, running from where an attacker gets in to what they reach. Click any box to jump to its inventory row, or a B-badge to jump to that boundary; hover a box to reveal its data flows. Everything reads statically below — the key resolves every mark and the tables carry every citation.
User / InputsClient / AdaptersAgent CoreTools / MCPExternal / DeployB1B2B3B4B5B6B7B8B9Local developer / CIidentityENTRYPOINTWorking-directoryproject contentDATASTOREon attack path — source (ingress)Textual TUICLIENTTUI approval promptCONTROLHeadless clientCLIENTHeadless approvalresolverCONTROLLocal agent-runtimeserverADAPTERon attack path — source (ingress)Agent loop and toolwiringORCHESTRATORon attack path — pass-throughHITL interrupt mapCONTROLShell allow-list checkCONTROLon attack path — control on the path (bypassed)Local-context promptinjectionPROMPTon attack path — pass-throughAuto-mode classifierCONTROLMCP readOnlyHintexemptionCONTROLSub-agent definitionsPROMPTModel resolution and LLMcallMODELSession checkpoint storeMEMORYon attack path — target (consequence)AGENTS.md memoryMEMORYShell execute toolTOOLon attack path — target (consequence)Filesystem toolsTOOLon attack path — target (consequence)Web toolsTOOLon attack path — pass-throughSSRF guardCONTROLMCP serversMCP_SERVEROutbound webEXTERNAL_SERVICEon attack path — source (ingress)Repository MCP configDEPLOY_SURFACEGitHub ActionDEPLOY_SURFACE
Familiesactors & inputsclient / adaptersagent coretools & datacontrolsexternal & deploy
Kindsentrypointdatastoreclientcontroladapterorchestratorpromptmodelmemorytoolmcp serverexternal servicedeploy surface
Marksboundary — worst threat: confirmed— potential (unanswered hypothesis)— partial (control covers part; remainder stated)— mitigatedattack path (origin → consequence)box on an attack path: source (ingress) pass-through control that failed target (consequence)faint arc = flow spanning 2+ lanes
Attack Paths
A cloned repository's own files reach the host shell in an unattended run
  1. Working-directory project content [PRAX-2026-08-12-004] The Makefile and file listing of whatever repository the agent was pointed at are attacker-authored content, read before any approval prompt exists.
  2. Local-context prompt injection [PRAX-2026-08-12-004] The detection script appends that content to the system prompt on every turn, unlabelled and in the highest-trust position in the context window.
  3. Agent loop and tool wiring [PRAX-2026-08-12-001] The loop cannot distinguish it from operator instruction and turns it into tool calls.
  4. Shell allow-list check [PRAX-2026-08-12-003] The only shell check that runs without a human matches each segment's first token, so an allow-listed interpreter carries the payload in its arguments.
  5. Shell execute tool [PRAX-2026-08-12-001] The command executes on the developer's machine or the CI runner with the operator's privileges.
A fetched web page rewrites files in the project with nobody in the loop
  1. Outbound web [PRAX-2026-08-12-004] An attacker-controlled page or search result — content nobody vetted and nothing labels as external.
  2. Web tools [PRAX-2026-08-12-004] It is converted to markdown and handed back as a tool result.
  3. Agent loop and tool wiring [PRAX-2026-08-12-004] The tool result re-enters the context verbatim and its instructions become the loop's next tool calls.
  4. Filesystem tools [PRAX-2026-08-12-002] In a headless run the write, edit and delete tools are auto-approved, so the injected instruction changes files on disk with no review and no configuration that would restore one.
A co-resident process on the developer's machine plants instructions that survive the session
  1. Local agent-runtime server [PRAX-2026-08-12-005] The agent-runtime API runs with authentication disabled, so any same-user process that finds the ephemeral port is accepted without ever proving it is the operator.
  2. Agent loop and tool wiring [PRAX-2026-08-12-005] Submitted inputs enter the running thread as ordinary conversation and steer the next turns.
  3. Session checkpoint store [PRAX-2026-08-12-010] Those turns are checkpointed into the unencrypted thread store, so they replay into the model's context whenever the session is resumed — the poisoning outlives the process that planted it.
Trust Boundaries — Threats & Governing Remit Rules
B1 Untrusted content entering the model context (untrusted-ingress) — 3 threats, 1 remit rules · worst: confirmed
R-01 partial MUST NOT treat content that arrives from tool results or retrieved sources ... as authoritative instructions that redefine the agent's goals, expand its scope, or override its approval gates.
STRIDEOWASPThreatStatus
TLLM01The working directory's Makefile and file listing are appended to the system prompt on every turn and tool results re-enter context verbatim, so a cloned repository or a fetched page writes into the highest-trust position in the context window with no provenance marker.confirmed PRAX-2026-08-12-004
SLLM01A project-supplied sub-agent definition's markdown body becomes that sub-agent's system prompt verbatim, letting repository content impersonate operator instruction inside a delegated run.confirmed PRAX-2026-08-12-014
TLLM01Nothing normalises or flags hostile Unicode in content entering the prompt, only in tool-call arguments shown at approval time — partial because the same detectors exist but are wired to the approval dialog, not the ingress path.partial libs/code/deepagents_code/unicode_security.py:140
remainder: detect_dangerous_unicode is applied to action-request arguments before approval, never to detect-script output, fetched page markdown, MCP results or memory files as they enter the context.
B2 Model decision to a side-effecting tool (tool-invocation) — 6 threats, 9 remit rules · worst: confirmed
R-19 partial Shell / command execution MUST require explicit human approval before the command runs.
R-21 gap An "allow everything" allow-list setting is out of bounds.
R-22 gap Absent an allow-list, approval is required in every execution context, including non-interactive and headless/CI runs.
R-24 partial Creating, writing, editing, or deleting files MUST require human approval.
R-25 partial Outbound web actions — `fetch_url`, `http_request`, `web_search` — MUST require human approval before the request is made.
R-26 partial Delegating to a sub-agent (`task`) and launching, updating, or cancelling an async sub-agent MUST require human approval.
R-28 partial The agent MUST NOT disable, weaken, or bypass the human-approval gate on side-effecting tools on its own initiative or in response to retrieved/tool content.
R-29 gap Destructive filesystem or shell operations MUST NOT execute without either human approval or execution inside an isolated sandbox backend.
R-30 gap Untrusted project content (`Makefile`, `.env`, committed config) MUST NOT drive a side-effecting action without passing the human-approval gate
STRIDEOWASPThreatStatus
EASI05Injected project content reaching the model in a headless run drives shell execution on the host through an allow-listed interpreter, because the allow-list matches the executable name and never the arguments it carries.confirmed PRAX-2026-08-12-001
ELLM03In a headless run every action other than execute is auto-approved — file writes and deletes, web fetches, search and sub-agent delegation all run with no gate, and no configuration restores approval for them.confirmed PRAX-2026-08-12-002
ELLM03The shell allow-list is not an execution boundary: the allow-all sentinel returns approval before any pattern check, and a restrictive list is enforced only against each segment's first token.confirmed PRAX-2026-08-12-003
TASI04An MCP server decides which of its own tools need review — a server-declared readOnlyHint with no destructive hint removes the tool from the interrupt map in Manual as well as Auto mode, and tool definitions are neither signed nor version-pinned after the trust prompt.confirmed PRAX-2026-08-12-007
R—The project's own threat model no longer matches the code it documents — it lists a built-in HTTP tool that does not exist and denies a URL guard that does — so the accepted-risk decisions covering this boundary rest on a stale inventory.confirmed PRAX-2026-08-12-013
ILLM10A model-supplied URL — which may have come from injected content — cannot be steered at loopback, private ranges or cloud metadata: the scheme is allow-listed, the resolved address is checked, every redirect hop is re-checked, and the connection is pinned to the validated IP.mitigated libs/code/deepagents_code/tools.py:81
B3 Loopback agent-runtime API (control-plane-exposure) — 2 threats, 1 remit rules · worst: confirmed
R-05 verified MUST bind a loopback interface only and MUST NOT expose the agent-runtime API to non-loopback interfaces or any non-local network.
STRIDEOWASPThreatStatus
SASI07The runtime server is spawned with authentication disabled, so any same-user process that finds the ephemeral port can submit inputs to the running thread, read conversation state, or push state updates; loopback binding and port randomness are the only barriers and neither is an authorization control.confirmed PRAX-2026-08-12-005
TASI06Messages injected through that unauthenticated API are indistinguishable from operator turns and are checkpointed with the rest of the thread, so they replay on resume rather than dying with the session (checked: sessions.py:285 and server.py:337 — no authentication, signing or provenance check exists on the state-update path).potential
B4 Conversation to the model provider (model-egress) — 2 threats, 1 remit rules · worst: potential
R-16 verified Conversation or project data MUST NOT be sent to third-party, sandbox, or provider destinations that retain it without the operator's awareness and opt-in.
STRIDEOWASPThreatStatus
ILLM02Everything the agent has read this turn — file contents, command output, fetched pages, and any credential that appeared in them — is sent to the operator-selected provider endpoint with no redaction pass on the request (checked: agent.py:2986 and the middleware stack — the only secret-redaction regex in the package runs on hook transcripts at hooks/transcript.py:53, not on model requests).potential
ILLM02Tracing to LangSmith is a second copy of the same conversation, but it activates only when the operator has supplied the API key and tracing environment variables.mitigated libs/code/deepagents_code/config.py:3105
B5 Memory and checkpoints re-entering the agent's reasoning (stored-state) — 2 threats, 1 remit rules · worst: confirmed
R-02 partial MUST NOT redefine, expand, or remove its own operating objectives, authorized scope, or safety gates on its own initiative.
STRIDEOWASPThreatStatus
TASI06Memory auto-save is on by default, so content the agent absorbed this session — including instructions read out of a repository or a fetched page — can be written into AGENTS.md and loaded back into the prompt in later sessions.partial libs/code/deepagents_code/memory_guard.py:95
remainder: the guard restores only the managed onboarding-name block; the rest of the memory file is agent-writable and re-enters the system prompt on every later session.
ELLM03Because headless runs auto-approve file writes, the agent can rewrite its own memory and skill files during an unattended run with no operator in the loop at the moment of the write.confirmed PRAX-2026-08-12-002
B6 Persisted conversation state on disk (data-at-rest) — 2 threats, 2 remit rules · worst: confirmed
R-15 gap Persisted conversation and session data MUST be protected at rest commensurate with its sensitivity (e.g. access-restricted file permissions or encryption at rest).
R-17 gap Persisted conversation/session data and memory MUST be retained only per the operator-configured retention/purge policy, and MUST NOT be kept indefinitely by default.
STRIDEOWASPThreatStatus
ILLM02The checkpoint database holds full conversation state including tool arguments and results — so anything the agent read, such as a .env printed by a command, is written verbatim — into a directory created with no explicit mode, unencrypted, with no retention or purge mechanism anywhere in the session, offload or config modules.confirmed PRAX-2026-08-12-010
ILLM02The neighbouring credential store in the same state directory is written atomically through an O_EXCL 0600 open with a follow-up chmod, so stored provider keys are not exposed to other local users.mitigated libs/code/deepagents_code/auth_store.py:247
B7 Provider credentials in the process environment (secret-material) — 2 threats, 2 remit rules · worst: confirmed
R-13 partial Credentials and secrets (provider API keys, tokens, passwords, environment secrets) MUST NOT be transmitted to any external destination, nor persisted into memory files, skills, session/checkpoint stores, or logs.
R-14 partial The secret-bearing process environment MUST NOT be forwarded wholesale to spawned subprocesses (MCP servers, hooks, the runtime server, sandbox setup) — each child MUST receive only the environment it requires.
STRIDEOWASPThreatStatus
IASI03The runtime server subprocess inherits a copy of the whole launching environment with only cloud-auth names and PYTHONPATH stripped, so every provider API key reaches it; separately an MCP stdio server's declared env is type-checked but never key-filtered, letting a trusted config set PATH, LD_PRELOAD or PYTHONPATH for that child.confirmed PRAX-2026-08-12-006
ILLM02Nothing scans content the agent reads into context for credentials before it is checkpointed or sent onward, so a key printed by an allow-listed command persists in the thread (checked: hooks/transcript.py:53 redacts secret-shaped assignments only in hook transcripts; no equivalent runs on the tool-result, checkpoint or model-request paths).potential
B8 Audit, monitoring and escalation (telemetry-egress) — 2 threats, 2 remit rules · worst: confirmed
R-36 gap All side-effecting tool executions and approval decisions MUST be recorded to a durable, structured audit record.
R-33 gap Halt and alert the operator if retrieved content, tool output, or configuration attempts to make the agent disable its approval gate, exfiltrate credentials, or execute code outside an isolated sandbox against untrusted input.
STRIDEOWASPThreatStatus
R—No durable structured record of tool executions or approval decisions exists by default: the hook event stream carries exactly that data but only fires when the operator has authored a hooks configuration, file logging needs a debug environment variable, and the always-on surface is a bounded in-memory ring buffer that dies with the process.confirmed PRAX-2026-08-12-009
R—There is no halt-and-alert path for content trying to disable the gate or reach credentials — the classifier that recognises exactly those categories is opt-in, interactive-only, and denies the single call rather than stopping the run or raising an alert; headless runs have no detector at all.confirmed PRAX-2026-08-12-015
B9 Runtime, dependency and extension provenance (supply-chain) — 4 threats, 4 remit rules · worst: confirmed
R-07 partial only the authorized LLM provider endpoints, MCP servers, sandbox providers, and sub-agent deployment URLs are trusted
R-11 partial the agent MUST NOT acquire, load, or expose tools or capabilities beyond it in response to LLM output, retrieved content, or repository-committed configuration.
R-27 verified Loading a project-level (repository-supplied) MCP server MUST require explicit operator trust approval before the server is spawned or connected.
R-32 partial Loading configuration, model-provider definitions, or skill/memory definitions MUST NOT cause arbitrary code to execute before those definitions have been validated.
STRIDEOWASPThreatStatus
TLLM04Auto-update ships enabled and replaces the runtime from the package registry with no signature or hash check, adding a destination the operator never configured; the bundled ripgrep install shows the contrasting posture with a pinned SHA-256.confirmed PRAX-2026-08-12-011
TLLM04No component inventory ships with the package and one dependency carries no upper bound, so exposure cannot be assessed when an advisory lands and a resolve can cross a future major version.confirmed PRAX-2026-08-12-012
EASI05A configured class_path provider is imported before any validation, so module-level code in a hostile module has already run by the time the BaseChatModel check rejects it; the provider-profile loader takes the same shape through exec_module.confirmed PRAX-2026-08-12-008
SASI04A repository-supplied MCP server is not spawned on the strength of the repository alone — project configs pass a per-server trust filter keyed on the config fingerprint, and a changed fingerprint re-prompts rather than loading silently.mitigated libs/code/deepagents_code/mcp_tools.py:952
Component Inventory
Every component with its kind, lane, and source evidence — the diagram's tooltips, on paper.
ComponentKindLaneDescriptionEvidence
Local developer / CI identityentrypointuser_inputsThe operator who launches dcode and is the sole authority for approvals, typing prompts into the TUI or piping them to the headless client.libs/code/deepagents_code/main.py:1529; tests/baselines/v1.3-opus5/deepagents-cli/deepagents-cli-remit.md:82
Working-directory project contentdatastoreuser_inputsThe project directory the agent is pointed at — its Makefile, file listing and tree, and any project-level .agents/ definitions — read by the runtime before any approval prompt exists.libs/code/deepagents_code/local_context.py:595; libs/code/deepagents_code/local_context.py:515
Textual TUIclientclient_adaptersThe interactive terminal front-end that collects operator prompts, renders streamed output, and hosts the approval dialog.libs/code/deepagents_code/app.py:2569; libs/code/deepagents_code/client/remote_client.py:157
TUI approval promptcontrolclient_adaptersThe interactive approval menu that shows the pending action and surfaces Unicode / homoglyph warnings before the operator approves or rejects.libs/code/deepagents_code/tui/widgets/approval.py:87; libs/code/deepagents_code/tui/widgets/approval.py:194
Headless clientclientclient_adaptersThe non-interactive / piped-stdin front-end used for scripting and CI, bounded by turn and time budgets.libs/code/deepagents_code/client/non_interactive.py:1342; libs/code/deepagents_code/client/non_interactive.py:1600
Headless approval resolvercontrolclient_adaptersThe headless run's stand-in for human approval: it checks shell commands against the allow-list and auto-approves every other action.libs/code/deepagents_code/client/non_interactive.py:831; libs/code/deepagents_code/client/non_interactive.py:897
Local agent-runtime serveradapterclient_adaptersAn ephemeral LangGraph dev subprocess on loopback that both front-ends drive over HTTP+SSE; spawned with authentication disabled and a copy of the launching process environment.libs/code/deepagents_code/client/launch/server.py:32; libs/code/deepagents_code/client/launch/server.py:352
Agent loop and tool wiringorchestratoragent_corecreate_cli_agent assembles the system prompt, tool set, middleware stack, subagents and checkpointer, and is where model output becomes tool calls.libs/code/deepagents_code/agent.py:2173; libs/code/deepagents_code/agent.py:2986
HITL interrupt mapcontrolagent_coreThe approval gate: the static map of side-effecting tools that raise an interrupt before execution, extended with non-read-only MCP tools.libs/code/deepagents_code/agent.py:2040; libs/code/deepagents_code/agent.py:2117
Shell allow-list checkcontrolagent_coreThe only shell control that applies without a human: a per-segment first-token match against the operator's allow-list, skipped entirely under the allow-all sentinel.libs/code/deepagents_code/config.py:3037; libs/code/deepagents_code/config.py:3063
Local-context prompt injectionpromptagent_coreMiddleware that runs a bash detection script in the backend and appends the working directory's Makefile, file listing and tree to the system prompt on every model call.libs/code/deepagents_code/local_context.py:691; libs/code/deepagents_code/local_context.py:642
Auto-mode classifiercontrolagent_coreAn opt-in, interactive-only LLM classifier that allows or denies proposed tool calls by category and fails closed to human review.libs/code/deepagents_code/auto_mode.py:115; libs/code/deepagents_code/auto_mode.py:129
MCP readOnlyHint exemptioncontrolagent_coreA gate-removal path: MCP tools whose server-declared metadata says readOnlyHint without a destructive hint are skipped when the interrupt map is built.libs/code/deepagents_code/auto_mode.py:382; libs/code/deepagents_code/agent.py:2132
Sub-agent definitionspromptagent_coreMarkdown sub-agent definitions discovered from user and project directories; the body after the YAML frontmatter becomes that sub-agent's system prompt with no content validation.libs/code/deepagents_code/subagents.py:67; libs/code/deepagents_code/subagents.py:170
Model resolution and LLM callmodelagent_coreOperator-selected provider/model resolution and instantiation, including the class_path escape hatch that imports an arbitrary module before validating it.libs/code/deepagents_code/model_config.py:426; libs/code/deepagents_code/config.py:4444
Session checkpoint storememoryagent_coreThe SQLite checkpoint database holding full conversation state — prompts, model output, tool arguments and results — so threads can be resumed.libs/code/deepagents_code/sessions.py:285; libs/code/deepagents_code/model_config.py:524
AGENTS.md memorymemoryagent_corePersistent memory files loaded into the prompt each session and, under the default auto-save prompt, written back by the agent itself.libs/code/deepagents_code/agent.py:2562; libs/code/deepagents_code/agent.py:2282
Shell execute tooltooltools_mcpThe shell-command tool exposed to the model when shell is enabled; the highest-consequence capability in the inventory.libs/code/deepagents_code/agent.py:2291; libs/code/deepagents_code/agent.py:1721
Filesystem toolstooltools_mcpThe read/write/edit/delete/search tools over the configured backend — the family the agent uses to change files in the operator's project.libs/code/deepagents_code/agent.py:179; libs/code/deepagents_code/agent.py:1380
Web toolstooltools_mcpBuilt-in outbound tools — web_search over Tavily and fetch_url, which converts a fetched page to markdown and returns it as a tool result.libs/code/deepagents_code/tools.py:319; libs/code/deepagents_code/tools.py:394
SSRF guardcontroltools_mcpScheme allow-list, private/loopback/link-local address rejection and DNS pinning applied to every URL the model supplies to fetch_url.libs/code/deepagents_code/tools.py:81; libs/code/deepagents_code/tools.py:163
MCP serversmcp_servertools_mcpOperator- and project-configured MCP servers (stdio subprocess or remote HTTP/SSE), their tool discovery, and the per-server trust filter applied before connection.libs/code/deepagents_code/mcp_tools.py:2359; libs/code/deepagents_code/mcp_tools.py:952
Outbound webexternal_serviceexternal_deployArbitrary HTTP/HTTPS destinations the agent fetches, plus the Tavily search API — content returned from here is attacker-influenceable.libs/code/deepagents_code/tools.py:285; libs/code/deepagents_code/tools.py:394
Repository MCP configdeploy_surfaceexternal_deployRepository-supplied .mcp.json server definitions — the checked-in file here declares two remote HTTP MCP endpoints — gated by a trust prompt before any server is spawned..mcp.json:2; libs/code/deepagents_code/mcp_tools.py:1004
GitHub Actiondeploy_surfaceexternal_deployThe published composite action that installs dcode with uvx and runs it headlessly inside a workflow, passing the workflow's prompt and shell allow-list.action.yml:490; action.yml:413
Extraction Notes
lane_fit: Two strains. The loopback agent-runtime server is a spawned local process, not a user-facing client, but it is the API surface both front-ends talk to, so it sits in client_adapters. And the upstream model provider endpoint has no node of its own — the model-resolution/LLM-call surface in agent_core carries it, so model-egress crosses the orchestrator-to-model edge rather than an agent_core-to-external_deploy one.
omissions: Arbitration: the findings JSON records both an LLM and an agentic code on several findings without naming a primary; where this graph must pick one it follows the KB. For the environment-forwarding finding the KB's credential/identity-scope row makes ASI03 primary and LLM02 the co-tag, so the threat is tagged ASI03 while the stored tag list leads with LLM02. For the MCP readOnlyHint finding the KB's runtime tool-definition row (rug pull / unverified tool metadata) is more specific than the missing-gate row, so it is tagged ASI04 rather than LLM03. The loopback-API finding keeps ASI07 — the KB's neighbours note assigns the channel-authentication defect there. No other stored tag disagrees with the KB. Components suspected but not modelled for want of a citation that holds in this snapshot: the remote sandbox backends (Daytona, Modal, Runloop, LangSmith, AgentCore) and the conversation offload path into them are present in the tree but no finding and no in-scope control chain attaches to them here; skills, plugins and their marketplace trust store are likewise real but were left out under the size discipline, with the MCP trust filter standing for the same operator-trust mechanism. The PyPI auto-update egress has no node of its own under the size discipline; its finding is carried as a supply-chain threat instead. All fifteen findings in the JSON are represented.
generated by: Opus 5 (1M context)