Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
39fd860
feat(cli): generate and review SECURITY.md
mldangelo-oai Aug 17, 2026
0074827
fix(cli): keep policy generation scoped and reviewable
mldangelo-oai Aug 17, 2026
f27e4cd
fix(cli): preserve policy evidence during generation
mldangelo-oai Aug 17, 2026
be2fb8f
fix(cli): preserve policy updates and cancellation
mldangelo-oai Aug 17, 2026
78c9325
fix(cli): retain previous policy files after updates
mldangelo-oai Aug 17, 2026
82c1cbe
fix(cli): bind policy drafts to their source guidance
mldangelo-oai Aug 17, 2026
1f36f9d
fix(cli): handle linked policies during preflight
mldangelo-oai Aug 17, 2026
2fd78b1
fix(cli): honor policy output options
mldangelo-oai Aug 17, 2026
53553bd
fix(cli): report policy failures in full output
mldangelo-oai Aug 17, 2026
233d2d5
fix(cli): preserve policy scope and user choices
mldangelo-oai Aug 17, 2026
b1de4d9
fix(cli): distinguish command names from option values
mldangelo-oai Aug 17, 2026
7f9b827
fix(ci): make policy checks portable
mldangelo-oai Aug 17, 2026
7c5b18d
fix(cli): keep component policy changes in scope
mldangelo-oai Aug 17, 2026
b1233a9
fix(cli): preserve the selected policy scope
mldangelo-oai Aug 17, 2026
63e50f8
fix(cli): protect reporting policies and clarify output errors
mldangelo-oai Aug 17, 2026
3ecd6c0
fix(cli): validate the complete policy checkout
mldangelo-oai Aug 17, 2026
2f89060
fix(cli): keep policy targets in Git worktrees
mldangelo-oai Aug 17, 2026
fe4d54d
fix(cli): protect enclosing policy checkouts
mldangelo-oai Aug 17, 2026
584d9df
fix(cli): keep policy Python lookup scoped
mldangelo-oai Aug 17, 2026
5c0acd8
fix(cli): normalize reporting policy directory casing
mldangelo-oai Aug 17, 2026
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
4 changes: 4 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@

FROM node:22-bookworm-slim@sha256:6c74791e557ce11fc957704f6d4fe134a7bc8d6f5ca4403205b2966bd488f6b3 AS package

RUN apt-get update \
&& apt-get install --no-install-recommends --yes python3 \
&& rm -rf /var/lib/apt/lists/*

WORKDIR /build/sdk/typescript

COPY sdk/typescript/package.json sdk/typescript/pnpm-lock.yaml ./
Expand Down
48 changes: 47 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Codex Security

`@openai/codex-security` is a CLI and TypeScript SDK for finding, validating, and fixing security vulnerabilities in your code.
`@openai/codex-security` is a CLI and TypeScript SDK for defining security policy and finding, validating, and fixing security vulnerabilities in your code.

**See the [Codex Security documentation](https://learn.chatgpt.com/docs/security/cli)** for more details.

Expand All @@ -16,6 +16,7 @@ Node.js 26.x; Python 3.10 or later; and access to Codex Security.
```bash
npm install @openai/codex-security
npx @openai/codex-security login
npx @openai/codex-security policy .
npx @openai/codex-security scan .
npx @openai/codex-security scan . --model gpt-5.6-terra --effort high
npx @openai/codex-security scan . --scan-prompt-file scan.md --post-scan-prompt-file follow-up.md
Expand Down Expand Up @@ -79,6 +80,51 @@ root cause, reuses saved matches, and identifies new, persisting, reopened,
resolved, or unknown findings. Missing findings remain unknown when coverage is
incomplete or their original location was not reviewed.

## Generate SECURITY.md

Generate a source-backed security policy for a repository or one component:

```bash
npx @openai/codex-security policy .
npx @openai/codex-security policy . --path services/api --knowledge-base architecture.md
```

The command first maps the system, builds a detailed threat model, and then
drafts a concise `SECURITY.md`. In a terminal, it asks about material unknowns,
shows the proposed diff, and asks before writing. Existing reporting instructions
and owner-confirmed policy decisions are preserved. Scans automatically read the
resulting root and nested `SECURITY.md` files.

For a noninteractive review, save a draft outside the repository and any enclosing
Git checkout:

```bash
npx @openai/codex-security policy . --headless --output-dir /path/outside/repository/policy --json
# Review and, if needed, edit the saved SECURITY.md draft.
npx @openai/codex-security policy . --apply /path/outside/repository/policy --write
```

Use the same repository and `--path` when applying a component draft. Applying
does not call the model. Before writing, it checks that the original policy,
inherited policies, and links to those policies have not changed. `--write`
requires a previously generated `--apply` draft. If you generated with a custom
`--plugin-path`, select that plugin again when applying a saved draft. Updates
keep the previous file at the reported recovery path; remove it only after other
writers have closed it and any edits are reconciled.

If a parent or sibling `SECURITY.md` links to the selected component's policy,
fix that link first. Otherwise, changing the component policy would also change
guidance outside the scope you reviewed.
Root policies also leave the reporting policies in `.github/SECURITY.md` and
`docs/SECURITY.md` unchanged.

The private artifact directory also contains `project-spec.md` and
`THREAT_MODEL.md`. Review these detailed documents before sharing them; only the
approved policy is applied to the repository. Generated policy is not owner
sign-off, and threat scenarios are not confirmed vulnerabilities. See the
[package README](sdk/typescript/README.md#generate-a-security-policy) for SDK use,
output formats, and generation options.

## Publish scan findings

Publish every finding from a completed scan to a Linear team:
Expand Down
161 changes: 161 additions & 0 deletions sdk/typescript/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,9 +197,170 @@ Some cybersecurity requests and protected findings require approval through
Trusted Access for Cyber. To apply or check your access, visit
[chatgpt.com/cyber](https://chatgpt.com/cyber).

## Generate a security policy

`policy` generates or updates the `SECURITY.md` that future scans read. It uses
the same Codex runtime, authentication, model settings, and bundled security
guidance as scans, but does not run vulnerability discovery or create a scan
record. Model turns are read-only; the SDK saves their responses in the private
artifact directory. Network access and web search are disabled. The command does
not enable apps or MCP servers.

```bash
npx @openai/codex-security policy .
npx @openai/codex-security policy . --path services/api
npx @openai/codex-security policy . --knowledge-base architecture.md --model gpt-5.6-terra --effort high
npx @openai/codex-security policy . --dry-run --json
```

The repository defaults to the current directory. `--path` selects one
repository-relative component directory. When invoked from a component inside a
Git checkout, the command still resolves inherited policies from the Git root.
It rejects Git settings that redirect that root outside the selected checkout.
An initialized submodule uses its own checkout root, including when selected
with `--path`. Draft output stays outside every enclosing checkout, and policy
link checks also protect those checkouts. Git metadata cannot be a policy target.
Existing root and nested `SECURITY.md` files compose from root to leaf; the
closest policy takes precedence when guidance conflicts.
If a `SECURITY.md` outside the selected component links to its policy, fix that
link first. This includes a broken link that would become active when the policy
is created. The command rejects these links to keep approval limited to the
selected scope.
Policy links must stay inside the repository. When drafting a root policy, the
command also protects separate reporting policies at `.github/SECURITY.md` and
`docs/SECURITY.md`.

Generation has three stages: a code-backed architecture specification, a detailed
threat model, and a concise policy draft. In an interactive terminal, the command
asks about facts that materially affect the policy, in groups of at most three
questions. It then shows the exact proposed diff and any decisions that need
owner review. Nothing is written into the repository without confirmation.
If both a ChatGPT sign-in and an API key are available, interactive generation
asks which one to use. Set `--auth chatgpt` or `--auth api-key` to choose
explicitly.

### Review and apply a saved draft

Use `--headless` or structured output to generate without questions or a write
prompt. Saved review notes retain material questions and decisions from every
stage, even if the final draft omits them. The default artifact directory is
under the Codex Security state directory; `--output-dir` selects an empty
directory outside the enclosing Git worktree.

```bash
npx @openai/codex-security policy . --path services/api \
--headless --output-dir /path/outside/repository/api-policy --json

# Review or edit /path/outside/repository/api-policy/SECURITY.md.
npx @openai/codex-security policy . --path services/api \
--apply /path/outside/repository/api-policy --write
```

`--apply` loads the saved draft without starting Codex. Omit `--write` to review
and confirm interactively. `--write` is available only with `--apply`, so a
noninteractive write always selects an existing draft. The repository and
component must match the draft. The original `SECURITY.md`, inherited policies,
and inherited policy links must be unchanged. The command writes the reviewed
bytes and verifies that the policy resolver can read them. It does not stage,
commit, or publish anything.

An update keeps the previous file so an editor with an old file handle cannot
lose a late save. The command tries to move it into the private artifact
directory. If that move fails, including across filesystems, it keeps a
`.SECURITY.md.*.previous` file beside the target. The CLI prints the recovery path
and includes `recoveryPath` in JSON output. Remove it only after other writers
have closed it and any edits are reconciled.

Avoid editing the target while application is in progress. A
`recovery_required` result means the replacement needs manual reconciliation.
Inspect its `recoveryPath` and `targetPath` before retrying.

Save edited drafts as UTF-8. If generation used a custom `--plugin-path`, pass
that option again when applying a saved draft; the saved metadata never selects
executable code. Plugin directories and ZIP files are both supported. Once a
write commits, the command finishes verification even if cancellation arrives.
If verification fails, it exits with an error and reports `written_unverified`
in JSON output. Review the written file and any reported `recoveryPath` before
retrying. A later repeated Ctrl-C or SIGTERM can force the command to stop if
verification does not finish.

The artifact directory contains:

| File | Purpose |
| ---------------------- | --------------------------------------------------------- |
| `SECURITY.md` | Editable policy draft. |
| `THREAT_MODEL.md` | Detailed, source-backed threat model. |
| `project-spec.md` | Architecture and security-boundary evidence. |
| `previous-SECURITY.md` | Original policy used for review and overwrite protection. |
| `policy-draft.json` | Target, policy hashes, revision, model, and review notes. |

After an update, `recovery-SECURITY-*.md` files can also contain retained previous
policies. They are not removed automatically.

Only the approved `SECURITY.md` is applied to the checkout. Keep detailed models
and intermediate artifacts private until they have been reviewed for disclosure.
Generated exclusions, accepted risks, and severity decisions still require the
appropriate owner's review; generation does not imply approval. This command
does not validate threat scenarios as vulnerabilities.

`--format md` writes the draft's Markdown to stdout. `--json` returns artifact
paths, review notes, status, and estimated cost. Explicit output options disable
interactive questions and write prompts. Global filters select fields from the
result; token options apply to the selected format, including Markdown. Progress
goes to stderr. With `--full-output`, policy and validation failures return
`ok: false` and an error message. Plain `--json` retains the recovery status and
paths described above when a write needs attention.
`--max-cost` applies to the entire generation, not separately to each stage.
If a stage cannot inspect its required source evidence, generation stops instead
of substituting a generic policy. Failures and cancellation preserve intermediate
documents, but an incomplete run cannot be applied; fix the reported problem and
start a new generation in a new output directory.

### Generate a policy from TypeScript

```ts
import {
CodexSecurity,
applySecurityPolicy,
securityPolicyDiff,
} from "@openai/codex-security";

const security = new CodexSecurity();
try {
const draft = await security.generatePolicy("/path/to/repository", {
path: "services/api",
knowledgeBasePaths: ["/path/to/architecture.md"],
onStage: (stage) => console.error(stage),
});

console.log(await securityPolicyDiff(draft));
// Obtain approval for this exact draft before calling:
// await applySecurityPolicy(draft);
} finally {
await security.close();
}
```

Use `security.preflightPolicy()` to validate local inputs without starting Codex.
`generatePolicy()` never edits the repository. It accepts `auth`, `path`,
`knowledgeBasePaths`, `outputDir`, `maxCostUsd`, and `signal`, plus progress and
cost callbacks. An optional `answerQuestions` callback supplies owner context;
it receives each group of up to three questions and a cancellation signal.
Without one, questions remain unresolved. Use
`loadSecurityPolicyDraft(repository, artifactDirectory, { path })` to load an
edited saved draft before reviewing and applying it. For a saved custom-plugin
draft, pass `{ pluginPath }` to `applySecurityPolicy()`. Applying returns
`{ targetPath, recoveryPath }`; `recoveryPath` is `null` when no existing file
was replaced. A `SecurityPolicyVerificationError` means the file was written
but verification failed; its `targetPath` identifies the file to inspect. A
`SecurityPolicyRecoveryError` means replacement needs manual reconciliation.
Both errors can identify a `recoveryPath` to preserve.

## CLI

```bash
npx @openai/codex-security policy
npx @openai/codex-security policy . --path services/api
npx @openai/codex-security scan
npx @openai/codex-security scan /path/to/repository
npx @openai/codex-security scan /path/to/repository --headless
Expand Down
2 changes: 2 additions & 0 deletions sdk/typescript/scripts/check-package.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ const distFiles = new Set(
"scan-dashboard",
"scan-history-renderer",
"scan-logs",
"security-policy",
"security-policy-cli",
"targets",
"trusted-executable",
"version",
Expand Down
Loading
Loading