Skip to content
Merged
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
3 changes: 3 additions & 0 deletions .agentpreflightignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Deliberately unsafe regression fixture. It is scanned directly in tests and demos.
test/fixtures/unsafe-repo
test/fixtures/configured-repo
15 changes: 15 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
---
name: Bug report
about: Report a reproducible false positive, false negative, or runtime issue
labels: bug
---

## What happened?

## Minimal safe reproduction

Do not include credentials, private code, or destructive payloads.

## Expected behavior

## Environment
11 changes: 11 additions & 0 deletions .github/ISSUE_TEMPLATE/rule_request.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
name: Rule request
about: Propose a new detection or remediation rule
labels: rule
---

## Threat pattern

## Why existing rules do not cover it

## Safe example and expected finding
10 changes: 9 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,18 @@ on:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
node-version: ${{ matrix.node-version }}
- run: npm test
- run: npm run lint
- run: node src/cli.js scan test/fixtures/safe-repo --fail-on low
- uses: ./
with:
mode: all
fail-on: critical
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# Changelog

## 0.3.0

- Added `.agentpreflight.json` policy files for rule severity overrides, reviewed ignores, and repository-default fail thresholds.
- Added baseline creation and baseline-aware scans so teams can prevent new findings without hiding existing debt.
- Added Markdown reports, GitHub Actions job summaries, rule explanations, and four additional supply-chain and verification checks.
- Added policy, baseline, CI, and rule-catalog documentation with working examples.

## 0.2.0

- Added scoped discovery for agent guidance, MCP configuration, scripts, package manifests, and GitHub Actions workflows.
- Added changed-files mode, severity thresholds, stable finding IDs, inline reviewed suppressions, JSON, and SARIF output.
- Added the `K14-coder/agent-preflight` composite GitHub Action.
- Added nine high-signal rules and a deliberately unsafe fixture repository.
3 changes: 3 additions & 0 deletions CODE_OF_CONDUCT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Code of Conduct

Be respectful, specific, and security-conscious. Do not post exploit payloads, credentials, private repositories, or personal information in issues, discussions, or pull requests. Report vulnerabilities through the process in [SECURITY.md](SECURITY.md).
183 changes: 162 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,47 +1,188 @@
# agent-preflight

> Scan a repository for risky instructions before giving it to an AI coding agent.
> Stop risky agent instructions before they reach Codex, Claude Code, Cursor, an MCP host, or a CI runner.

[![CI](https://github.com/K14-coder/agent-preflight/actions/workflows/ci.yml/badge.svg)](https://github.com/K14-coder/agent-preflight/actions/workflows/ci.yml) [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) [![Local only](https://img.shields.io/badge/privacy-local--only-0f766e)](#privacy-model)

AI coding tools read instructions and execute workflows with the permissions you give them. `agent-preflight` is a local-first security gate that scans the files most likely to influence that behavior: agent guidance, MCP configuration, package scripts, installers, and GitHub Actions workflows.

It never executes an MCP server, evaluates a script, uploads repository content, or requires an API key.

## The 30-second setup

Add a pull-request gate to your repository:

```yaml
name: Agent preflight
on:
pull_request:
paths:
- "**/*.md"
- "**/*.json"
- "**/*.yml"
- "**/*.yaml"
- "**/*.sh"

permissions:
contents: read

jobs:
scan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: K14-coder/agent-preflight@v0.3.0
with:
mode: changed
base: ${{ github.event.pull_request.base.sha }}
fail-on: high
```

The action fails on new high- or critical-severity findings and exposes `score` and `findings` as step outputs.

## Why v0.3 is useful in a real repository

`agent-preflight` is a local, zero-dependency CLI for a simple question: *is this repository asking my agent to do something surprising?* It looks for common prompt-injection, credential-discovery, destructive-command, encoded-execution, and symbolic-link patterns before an agent receives broad filesystem or shell access.
Security gates fail when they force a team to clean up every historical problem before they can protect the next pull request. v0.3 adds reviewed policy files and baselines, so the first adoption can report known debt while still blocking newly introduced high-risk instructions.

```bash
# Capture the current reviewed state once.
node src/cli.js baseline . --output .agentpreflight-baseline.json

# Fail only on findings that are not in that baseline.
node src/cli.js scan . --baseline .agentpreflight-baseline.json --fail-on high
```

Commit both the baseline and the policy review that approved it. Baselines are evidence of accepted risk, not a way to silence unknown findings.

## What a finding looks like

```text
CRITICAL APF002 AGENTS.md:4:6
Remote content is piped directly into a shell.
Fix: Download, inspect, checksum, and run a pinned artifact instead of piping remote content to a shell.
```

Try the deliberately unsafe demo repository from a checkout:

```bash
git clone https://github.com/K14-coder/agent-preflight.git
cd agent-preflight
node src/cli.js /path/to/untrusted-repository --json
npm test
npm run demo
```

## Scan modes

```bash
# All agent-facing surfaces in a repository
node src/cli.js scan /path/to/repository --fail-on high

# Only files changed from a reviewed base
node src/cli.js scan . --mode changed --base origin/main --fail-on high

# Integrate with another tool or upload results to GitHub code scanning
node src/cli.js scan . --format sarif --output agent-preflight.sarif
```

To upload SARIF in GitHub Actions:

```yaml
- run: node src/cli.js scan . --format sarif --output agent-preflight.sarif --fail-on none
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: agent-preflight.sarif
```

It exits with code `2` when it finds a high-severity pattern, which makes it usable in pre-commit hooks and CI. Once published to npm, it can be invoked with `npx agent-preflight`.
## What it scans

By default, the scanner limits itself to agent-facing surfaces so normal application code does not create noise:

- `AGENTS.md`, `CLAUDE.md`, `SKILL.md`, `README.md`, and other Markdown guidance
- MCP JSON/YAML configuration
- `package.json` and installer or shell scripts
- GitHub Actions workflow files

## What it checks
Use `--all-files` when auditing a repository more broadly.

- Downloads piped into a shell
- Encoded payloads that appear to execute
- Forced recursive deletion
- Attempts to discover common credential locations
- Attempts to direct agents around earlier safeguards
- Symbolic links that deserve manual review
## Built-in checks

This is a lightweight heuristic, not a security guarantee. Review findings and run unknown code in an isolated environment.
| Rule | Risk | Default severity |
| --- | --- | --- |
| `APF001` | Instruction override | High |
| `APF002` | Remote content piped to a shell | Critical |
| `APF003` | Encoded payload execution | Critical |
| `APF004` | Recursive forced deletion | High |
| `APF005` | Credential discovery | High |
| `APF006` | Potential credential exfiltration | Critical |
| `APF007` | Dynamic evaluation of external content | Medium |
| `APF008` | MCP shell launcher | Medium |
| `APF009` | Unpinned GitHub Action | Medium |
| `APF010` | Write-capable workflow token | Medium |
| `APF011` | Hidden Unicode control character | High |
| `APF012` | Remote instruction loading | High |

For an intentional fixture or reviewed false positive, append `agent-preflight: allow` on the same line. Keep suppressions rare and explain them in review.
## Policy and suppressions

## Development
Choose the policy that fits the environment:

```bash
npm test
--fail-on critical # only block the highest-risk findings
--fail-on high # default
--fail-on medium # use for hardening programs
--fail-on none # report only
```

## Privacy
For a reviewed, intentional exception, add a narrow source-line suppression:

The CLI never sends repository content, filenames, telemetry, or diagnostics over the network. It only reads the directory you pass to it.
```text
agent-preflight: allow=APF009
```

## Contributing
Suppressions are intentionally local and visible in code review. A clean scan is not a security guarantee; review any finding and run untrusted repositories in an isolated environment.

To omit an intentional fixture or generated directory, add a repository-relative path to `.agentpreflightignore`. Directory entries apply to their contents; keep ignores narrow and explain them in review.

### Versioned policy

Check in `.agentpreflight.json` to make policy visible in review:

```json
{
"policy": { "failOn": "high" },
"ignore": ["docs/generated"],
"rules": {
"APF009": "low",
"APF015": "off"
}
}
```

Issues and focused pull requests are welcome. Please read [CONTRIBUTING.md](CONTRIBUTING.md) and report vulnerabilities through [SECURITY.md](SECURITY.md).
`off` must be used sparingly. Prefer lowering severity when a control is still worth tracking. See [policy guidance](docs/policies.md), the [full rule catalog](docs/rules.md), and [CI integrations](docs/integrations.md).

## Keywords
### Explain a finding

```bash
node src/cli.js explain APF002
```

This prints the rule’s default severity, why it fires, and its remediation. Use it in issue triage rather than treating a rule ID as an opaque error.

## Privacy model

`agent-preflight` is offline by design. It makes no network requests, collects no telemetry, and reads only the repository you explicitly scan. It does not start MCP servers or execute detected commands.

## Roadmap

- Baseline files and finding-delta reports for large existing repositories
- Reusable policy packs for Codex, Claude Code, Cursor, and MCP deployments
- Signed npm package and GitHub release automation
- More syntax-aware rules with focused false-positive regression fixtures

## Contributing

AI agent security, coding agent safety, prompt injection detection, Claude Code security, Codex security, Cursor security, repository supply-chain security.
Read [CONTRIBUTING.md](CONTRIBUTING.md), [CODE_OF_CONDUCT.md](CODE_OF_CONDUCT.md), and [SECURITY.md](SECURITY.md). Rule proposals need a safe reproduction fixture and an expected finding ID.

## License

Expand Down
60 changes: 60 additions & 0 deletions action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
name: "Agent Preflight"
description: "Block risky AI-agent instructions, MCP configurations, scripts, and workflows before they merge."
author: "agent-preflight contributors"
branding:
icon: shield
color: purple
inputs:
mode:
description: "Scan all agent-facing files or only files changed from the supplied base ref."
required: false
default: all
base:
description: "Git ref or commit SHA used when mode is changed."
required: false
default: ""
fail-on:
description: "Minimum severity that fails the action: critical, high, medium, low, or none."
required: false
default: high
format:
description: "Output format: text, json, or sarif."
required: false
default: text
config:
description: "Optional path to an agent-preflight policy file."
required: false
default: ""
baseline:
description: "Optional path to a reviewed baseline file. Matching findings are reported as known debt."
required: false
default: ""
all-files:
description: "Scan every text file instead of only agent-facing surfaces."
required: false
default: "false"
outputs:
score:
description: "Risk score from 0 to 100."
findings:
description: "Number of findings."
runs:
using: composite
steps:
- id: scan
shell: bash
env:
APF_MODE: ${{ inputs.mode }}
APF_BASE: ${{ inputs.base }}
APF_FAIL_ON: ${{ inputs.fail-on }}
APF_FORMAT: ${{ inputs.format }}
APF_CONFIG: ${{ inputs.config }}
APF_BASELINE: ${{ inputs.baseline }}
APF_ALL_FILES: ${{ inputs.all-files }}
run: |
args=(scan "$GITHUB_WORKSPACE" --mode "$APF_MODE" --fail-on "$APF_FAIL_ON" --format "$APF_FORMAT")
if [ -n "$APF_BASE" ]; then args+=(--base "$APF_BASE"); fi
if [ -n "$APF_CONFIG" ]; then args+=(--config "$APF_CONFIG"); fi
if [ -n "$APF_BASELINE" ]; then args+=(--baseline "$APF_BASELINE"); fi
if [ "$APF_ALL_FILES" = "true" ]; then args+=(--all-files); fi
node "$GITHUB_ACTION_PATH/src/cli.js" "${args[@]}"
24 changes: 24 additions & 0 deletions docs/integrations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# Integrations

## GitHub Actions

Use the composite action from [examples/github-action.yml](../examples/github-action.yml). The action writes `score` and `findings` to step outputs and appends a Markdown summary when GitHub provides `GITHUB_STEP_SUMMARY`.

For changed-files mode, `actions/checkout` must use `fetch-depth: 0` and `base` should be the pull request base SHA. That makes the comparison deterministic even when a branch is rebased.

## SARIF

SARIF lets GitHub Code Scanning display findings at exact source locations:

```yaml
- run: node src/cli.js scan . --format sarif --output agent-preflight.sarif --fail-on none
- uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: agent-preflight.sarif
```

Keep the scan itself local. Uploading SARIF is an intentional GitHub action, not behavior performed by the CLI.

## Markdown and JSON

`--format markdown` is designed for pull-request comments and incident tickets. `--format json` provides the full stable finding record, including `ruleId`, severity, surface, source location, remediation, and fingerprint.
Loading
Loading