Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion sdk/typescript/_bundled_plugin/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "codex-security",
"version": "0.1.14",
"version": "0.1.15",
"description": "Codex Security workflows for security scans, analysis, and investigation.",
"author": {
"name": "OpenAI"
Expand Down
10 changes: 9 additions & 1 deletion sdk/typescript/_bundled_plugin/.mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,15 @@
"PYTHON",
"CODEX_SECURITY_KNOWLEDGE_BASE",
"CODEX_SECURITY_SCAN_ROOT",
"CODEX_SECURITY_STATE_DIR"
"CODEX_SECURITY_STATE_DIR",
"CODEX_SECURITY_TARGET_PATHS_FILE",
"HTTP_PROXY",
"HTTPS_PROXY",
"ALL_PROXY",
"NO_PROXY",
"SSL_CERT_FILE",
"REQUESTS_CA_BUNDLE",
"NODE_EXTRA_CA_CERTS"
],
"tool_timeout_sec": 86400
}
Expand Down
Binary file modified sdk/typescript/_bundled_plugin/mcp/mcp-app.html.br
Binary file not shown.
Binary file modified sdk/typescript/_bundled_plugin/mcp/server.mjs.br.part-000
Binary file not shown.
Binary file modified sdk/typescript/_bundled_plugin/mcp/server.mjs.br.part-001
Binary file not shown.
57 changes: 0 additions & 57 deletions sdk/typescript/_bundled_plugin/preflight/capability-profiles.toml
Original file line number Diff line number Diff line change
@@ -1,16 +1,5 @@
version = 1

[capabilities.deep_scan_phase_skills]
kind = "plugin_skills"
plugin = "codex-security"
required = [
"attack-path-analysis",
"finding-discovery",
"security-scan",
"threat-model",
"validation",
]

[capabilities.delegated_workers]
kind = "runtime"
check = "delegation_available"
Expand Down Expand Up @@ -45,15 +34,6 @@ op = "=="
value = true
default = true

[capabilities.native_multi_agent_v2]
kind = "multi_agent_mode"
owner = "native"
version = "v2"

[capabilities.sdk_v2_child_config_compatible]
kind = "config_absent"
path = "agents.max_threads"

[profiles.security_diff_scan]
description = "Capabilities for Git-backed Codex Security diff scans."

Expand Down Expand Up @@ -98,21 +78,6 @@ reason = "Enabling goals makes long scans easier to resume and audit."
[profiles.deep_security_scan]
description = "Capabilities for deep repository-wide Codex Security scans."

[[profiles.deep_security_scan.requirements]]
capability = "deep_scan_phase_skills"
severity = "block"
reason = "Deep scan depends on Codex Security phase skills loaded in the current runtime."

[[profiles.deep_security_scan.requirements]]
capability = "native_multi_agent_v2"
severity = "block"
reason = "Deep scan launches SDK discovery workers with native Subagents v2; legacy V1 and bridge-owned parent configurations are incompatible with that worker runtime."

[[profiles.deep_security_scan.requirements]]
capability = "sdk_v2_child_config_compatible"
severity = "block"
reason = "Deep scan child sessions inherit Codex configuration while enabling Subagents v2, so the legacy agents.max_threads setting must be removed before those sessions can start."

[[profiles.deep_security_scan.requirements]]
capability = "goal_tools"
severity = "suggest"
Expand Down Expand Up @@ -144,28 +109,6 @@ summary = "Recommended Codex setup for deep repository-wide scans."
path = "features.goals"
value = true

[[profiles.deep_security_scan.remediation.variants]]
mode = "v1"

[[profiles.deep_security_scan.remediation.variants.patches]]
kind = "remove"
path = "agents.max_threads"

[[profiles.deep_security_scan.remediation.variants.patches]]
path = "features.multi_agent_v2.enabled"
value = true

[[profiles.deep_security_scan.remediation.variants.patches]]
path = "features.multi_agent_v2.max_concurrent_threads_per_session"
value = 4

[[profiles.deep_security_scan.remediation.variants]]
mode = "v2"

[[profiles.deep_security_scan.remediation.variants.patches]]
kind = "remove"
path = "agents.max_threads"

[[routes]]
skill = "security-diff-scan"
profile = "security_diff_scan"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ When the profile includes remediation patches, present the concrete config delta

Some remediation patches have `kind = "host_setting"`. Present those as host-level setup guidance, not as edits to persistent Codex config.

Deep Security Scan uses MCP-owned SDK sessions rather than the parent thread's worker pool. Its preflight requires native V2 but does not derive outer worker concurrency from the parent session cap or require parent delegation depth. When migrating a legacy V1 configuration for Deep Security Scan, remediation removes `agents.max_threads`, sets `features.multi_agent_v2.enabled = true`, and sets `features.multi_agent_v2.max_concurrent_threads_per_session = 4`. The coordinator overrides each child session's cap from the per-user deep-scan configuration. Codex rejects the legacy V1 thread setting and explicit V2 mode together.
Deep Security Scan uses MCP-owned SDK sessions rather than the parent thread's worker pool. Its preflight does not require a particular parent delegation runtime, ownership, capacity, or depth. Discovery workers inherit the scan's model and run under the verified read-only worker sandbox.

Do not warn merely because a user's value differs from the profile's suggested patch. Warn or block only when the evaluated capability requirement is unmet.

Expand Down
22 changes: 15 additions & 7 deletions sdk/typescript/_bundled_plugin/references/final-report.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,21 @@ Use `report.md` as the primary readable entry point. Explain report-relevant art

In the final response, link the generated markdown report path as the primary readable artifact.

Every scan mode uses the same final report pipeline. The model authors canonical JSON only; it must not author, repair, or treat an existing `report.md` as input. For an app-backed running scan, author `scan-manifest.json` as an unsealed draft and omit `scan.sealedAt` and `scan.artifacts`; finalization owns the exact workbench timestamps, seal, artifact digests, and derived finding identities. `complete-scan` invokes finalization, which validates and enriches the canonical JSON, seals the canonical JSON and evidence artifacts, then deterministically generates and validates `report.md` as an unsealed downstream projection. Missing report prose must be added to the structured canonical fields rather than recovered from a separately authored report.
Every scan mode uses the same final report pipeline. For compact Standard and Deep scans, submit canonical semantics with `record_codex_security_scan_draft({ scanId, handoffClaimToken?, scope?, threatModel?, findings, coverage })`. The workbench writes the unsealed canonical draft and supplies the authoritative target, exact workbench timestamps, and derived finding identities. Other modes retain their existing canonical JSON workflow. No mode authors, repairs, or treats an existing `report.md` as input. `complete-scan` invokes finalization, which validates and enriches the canonical JSON, seals the canonical JSON and evidence artifacts, then deterministically generates and validates `report.md` as an unsealed downstream projection. Missing report prose must be supplied in the structured canonical semantics rather than recovered from a separately authored report.

When `complete_codex_security_scan` is available, use it to complete the scan. In Codex CLI or another terminal/chat host without that tool, run `python <plugin_dir>/scripts/finalize_scan_contract.py --scan-dir <scan_dir> --source-root <repo_root>` after writing the completed canonical JSON. Do not mark the scan goal complete until this command succeeds and the generated markdown report exists.
For each surviving compact candidate, supply the evidence-supported lowercase vulnerability-family `ruleId`; `taxonomy: { category, cwe }` using the candidate's exact `cwe_ids`; verified locations; and `provenance.source`, using `"local_plugin"` only when this plugin actually discovered the finding. Preserve the canonical candidate identity and genuine worker or source provenance in the existing finding extensions. A candidate with no known CWE retains `cwe: []`; never invent a classification. Include optional `codeEvidence` only when its actual code is nonempty and every referenced evidence ID is present.

Before completion, verify on disk that the workflow-owned `scan-manifest.json`, `findings.json`, and `coverage.json` exist and contain the completed canonical JSON. Completion is finalization only: it validates and seals already-authored canonical artifacts and generates `report.md`; it does not create missing artifacts or run skipped scan phases.
Supply semantic coverage as `{ completeness, surfaces, explicitExclusions, deferred }`, with each surface using the actual `label` and one existing `disposition`. Mark coverage `partial` when a deferred item or `needs_follow_up` surface remains; preserve its real reason and supporting context. Each deferred item needs a meaningful reason; preserve any existing `id` or `candidateId`. The workbench derives a missing ID from its candidate identity or stable deferred-work details. Open questions may be nonempty strings or `{ question, followUpPrompt? }` objects. The workbench derives target and scope metadata, scope include and exclude paths, coverage mode and inventory strategy, finding identities and fingerprints, and surface IDs. Do not put those workbench-owned values or top-level coverage receipt references into the semantic draft.

If any required scan phase, canonical-artifact write, or on-disk existence check fails before completion, stop the current response and surface the exact workflow blocker. Do not call completion with missing artifacts, return a final report or no-findings result, satisfy a structured output schema, or emit benchmark JSON. Leave the durable scan available for a later continuation instead of canceling or failing it solely because canonical assembly is blocked.
After a compact Standard or Deep draft is accepted, call `complete_codex_security_scan({ scanId, handoffClaimToken? })`, then read canonical results with `get_codex_security_completed_scan({ scanId, handoffClaimToken? })`. For diff or another existing terminal/chat workflow without the completion tool, retain `python <plugin_dir>/scripts/finalize_scan_contract.py --scan-dir <scan_dir> --source-root <repo_root>` after writing the completed canonical JSON. Do not mark the scan goal complete until finalization succeeds and the generated markdown report exists.

After `complete_codex_security_scan` succeeds, include its returned `usage.totalTokens`, `usage.inputTokens`, and `usage.cachedInputTokens` in the final response when `usage.coverage` is `complete` or `partial`; explicitly label a partial measurement. If coverage is `unavailable`, say that token usage could not be measured instead of reporting zero or estimating a cost. Report only measured completion metadata in a terminal/chat host. Token usage is workbench metadata, not a reason to modify sealed scan artifacts or the deterministic report.

Before compact Standard or Deep completion, require `record_codex_security_scan_draft` to succeed. Existing diff and legacy workflows continue to verify their canonical JSON before completion. Completion is finalization only: it validates and seals already-recorded canonical artifacts and generates `report.md`; it does not create missing artifacts or run skipped scan phases.

An MCP `-32602` input rejection, an `isError: true` result reporting `Input validation error`, or an explicit pre-write rejection of complete coverage containing deferred work or a follow-up surface makes no draft write. Correct only the named paths in the same draft, preserving all valid findings, fields, evidence, and deferred work; retry the same scan at most twice. Stop after the first accepted draft. Do not blindly retry an ambiguous transport or write failure.

For any other required scan phase, canonical-artifact write, or on-disk existence check that fails before completion, stop the current response and surface the exact workflow blocker. Do not call completion with missing artifacts, return a final report or no-findings result, satisfy a structured output schema, or emit benchmark JSON. Leave the durable scan available for a later continuation instead of canceling or failing it solely because canonical assembly is blocked.

If `complete_codex_security_scan` or the terminal/chat finalizer fails, stop the current response and surface the exact MCP or finalizer error. Do not retry completion in the same response, return a final report or no-findings result, satisfy a structured output schema, or emit benchmark JSON. Leave the durable scan available for a later continuation instead of canceling or failing it solely because completion failed.

Expand All @@ -34,7 +42,7 @@ Canonical report semantics live in these fields:
- `scan-manifest.json`: optional `scan.hardening.portfolioPath` for the derived, unsealed design portfolio at `hardening/hardening.md`
- `coverage.json`: `surfaces` including `riskArea` and `notes`, plus `openQuestions`

For a whole-repository Deep scan, keep `coverage.inventoryStrategy` as `repository`; repeated discovery is workflow metadata, not a different inventory strategy.
For a whole-repository Deep scan, the workbench derives `coverage.inventoryStrategy: "repository"` in the stored coverage document; repeated discovery is workflow metadata, not a different inventory strategy. Do not include `inventoryStrategy` in `record_codex_security_scan_draft`.

Older v1 producers may omit the new optional fields. Finalization uses explicit JSON-derived fallback text in that case; it never reads a pre-existing report to fill gaps.

Expand All @@ -53,11 +61,11 @@ Set the finding category and CWE from the primary broken control. Do not add sec

Examples that should normally become separate final findings include SQL API modes such as `execute`, `executemany`, and `executescript`; deserializer variants such as `pickle.load`, `pickle.loads`, `yaml.load`, and `yaml.load_all`; distinct path/file helper calls; SSRF modes with different destination controls; and missing-auth protected actions such as create, delete, reset, admin, and job-trigger endpoints.

For a standard repository or scoped-path scan, assemble the canonical JSON from the enriched `<discovery_dir>/candidate_ledger.jsonl`. Map each nested `validation` record into the finding's validation fields, map its confidence and rationale into top-level `confidence.level` and `confidence.rationale`, and map each nested `attack_path` record into dataflow, reachability, severity, and change conditions. Canonical `severity.changeConditions` must be one non-empty string; when `attack_path.change_conditions` contains multiple strings, join them into one prose string before writing `findings.json`.
For a Standard or Deep repository or scoped-path scan, read the same enriched candidates with `list_codex_security_candidates`. Map each nested `validation` record into the finding's validation fields, map its confidence and rationale into top-level `confidence.level` and `confidence.rationale`, and map each nested `attack_path` record into dataflow, reachability, severity, and change conditions. Canonical `severity.changeConditions` must be one non-empty string; when `attack_path.change_conditions` contains multiple strings, join them into one prose string before writing `findings.json`. Submit those semantics through `record_codex_security_scan_draft`.

Apply row outcomes in this order: validation disposition `reportable` plus attack-path decision `reportable` becomes a finding with its distinct instance and all relevant entrypoint, root-control, sink, and supporting locations; otherwise, a `deferred` result from either phase becomes `needs_follow_up` coverage and a `coverage.deferred` entry using the recorded uncertainty or proof gap; otherwise, validation disposition `not_applicable` becomes `not_applicable` coverage; otherwise, validation disposition `suppressed` or attack-path decision `ignore` becomes `rejected` coverage. A missing required phase record leaves the candidate unresolved and prevents complete coverage. Do not require phase receipts, per-candidate narratives, or another reconciliation pass.

Diff, deep, and resumed legacy scans may still provide per-candidate ledgers, validation closure tables, and repository coverage ledgers. When those artifacts exist, retain their traceability: start from reportable/surviving rows, preserve exact affected locations, and map suppressed, not-applicable, or deferred rows to public-facing coverage outcomes. Do not silently drop a seeded row because a same-family neighbor survived.
Diff and resumed legacy scans may still provide per-candidate ledgers, validation closure tables, and repository coverage ledgers. When those artifacts exist, retain their traceability: start from reportable/surviving rows, preserve exact affected locations, and map suppressed, not-applicable, or deferred rows to public-facing coverage outcomes. Do not silently drop a seeded row because a same-family neighbor survived.

## Report Structure

Expand Down
Loading
Loading