agentci-guard 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +144 -0
- package/SECURITY.md +23 -0
- package/action.yml +42 -0
- package/dist/cli.d.ts +1 -0
- package/dist/cli.js +718 -0
- package/dist/cli.js.map +1 -0
- package/dist/index.d.ts +135 -0
- package/dist/index.js +638 -0
- package/dist/index.js.map +1 -0
- package/docs/demo.svg +47 -0
- package/docs/demo.tape +34 -0
- package/docs/real-world-findings.md +79 -0
- package/docs/rules.md +33 -0
- package/docs/threat-model.md +32 -0
- package/examples/hardened/.github/workflows/ai-agent.yml +18 -0
- package/examples/vulnerable/.github/workflows/ai-agent.yml +29 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 David Wu
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
# AgentCI Guard
|
|
2
|
+
|
|
3
|
+
AgentCI Guard is a CLI and GitHub Action that detects unsafe AI coding-agent usage in CI/CD workflows.
|
|
4
|
+
|
|
5
|
+
It focuses on one high-risk pattern: untrusted GitHub event content reaching an AI agent that has secrets, write permissions, shell access, or unsafe checkout behavior.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
> The animated terminal demo is generated from [`docs/demo.tape`](docs/demo.tape) — run `vhs docs/demo.tape` to produce `docs/demo.gif`.
|
|
10
|
+
|
|
11
|
+
## What It Detects
|
|
12
|
+
|
|
13
|
+
- AI-agent usage in `.github/workflows/*.yml`
|
|
14
|
+
- `pull_request_target` combined with AI agents
|
|
15
|
+
- PR/issue/comment/review/branch/commit content passed into prompts or shell commands
|
|
16
|
+
- `contents: write`, `pull-requests: write`, or other broad write scopes near AI usage
|
|
17
|
+
- `secrets.*`, `GITHUB_TOKEN`, and token-like environment variables in agent jobs
|
|
18
|
+
- shell access combined with AI usage
|
|
19
|
+
- unpinned third-party AI actions
|
|
20
|
+
- checkout of untrusted PR head code in privileged contexts
|
|
21
|
+
|
|
22
|
+
## CLI Quickstart
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
# Run without installing
|
|
26
|
+
npx agentci-guard scan .
|
|
27
|
+
|
|
28
|
+
# Or install globally
|
|
29
|
+
npm install -g agentci-guard
|
|
30
|
+
|
|
31
|
+
agentci scan .
|
|
32
|
+
agentci scan . --json
|
|
33
|
+
agentci scan . --sarif agentci-results.sarif
|
|
34
|
+
agentci explain agentci/untrusted-ai-write-token
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Exit codes:
|
|
38
|
+
|
|
39
|
+
- `0`: no findings at or above `--fail-on`
|
|
40
|
+
- `2`: at least one finding at or above `--fail-on`
|
|
41
|
+
- `1`: scanner error
|
|
42
|
+
|
|
43
|
+
Default fail threshold is `high`.
|
|
44
|
+
|
|
45
|
+
## GitHub Action
|
|
46
|
+
|
|
47
|
+
```yaml
|
|
48
|
+
name: agentci-guard
|
|
49
|
+
on: [pull_request, push]
|
|
50
|
+
|
|
51
|
+
permissions:
|
|
52
|
+
contents: read
|
|
53
|
+
security-events: write
|
|
54
|
+
|
|
55
|
+
jobs:
|
|
56
|
+
scan:
|
|
57
|
+
runs-on: ubuntu-latest
|
|
58
|
+
steps:
|
|
59
|
+
- uses: actions/checkout@v4
|
|
60
|
+
- uses: David-Wu1119/agentci-guard@v0
|
|
61
|
+
with:
|
|
62
|
+
path: .
|
|
63
|
+
sarif: agentci-results.sarif
|
|
64
|
+
fail-on: high
|
|
65
|
+
- uses: github/codeql-action/upload-sarif@v3
|
|
66
|
+
if: always()
|
|
67
|
+
with:
|
|
68
|
+
sarif_file: agentci-results.sarif
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### Outputs
|
|
72
|
+
|
|
73
|
+
The action sets `findings`, `critical`, `high`, `medium`, `low`, and `sarif-path` so later steps can react:
|
|
74
|
+
|
|
75
|
+
```yaml
|
|
76
|
+
- uses: David-Wu1119/agentci-guard@v0
|
|
77
|
+
id: agentci
|
|
78
|
+
with:
|
|
79
|
+
fail-on: none
|
|
80
|
+
- if: steps.agentci.outputs.critical != '0'
|
|
81
|
+
run: echo "::warning::${{ steps.agentci.outputs.critical }} critical finding(s)"
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
If `agentci.config.json` exists in the scanned path it is picked up automatically (see [Suppressing Findings](#suppressing-findings)).
|
|
85
|
+
|
|
86
|
+
## Example Finding
|
|
87
|
+
|
|
88
|
+
```text
|
|
89
|
+
CRITICAL agentci/untrusted-ai-write-token
|
|
90
|
+
File: .github/workflows/ai-agent.yml / job: claude
|
|
91
|
+
Evidence: untrusted trigger + AI usage + write permissions + untrusted GitHub event context
|
|
92
|
+
|
|
93
|
+
Why:
|
|
94
|
+
An attacker can place prompt-injection text in a PR, issue, or comment. If that text reaches an AI agent with repository write permissions, the agent can be induced to modify code, comments, workflows, or releases.
|
|
95
|
+
|
|
96
|
+
Fix:
|
|
97
|
+
- Do not run privileged AI agents on untrusted triggers.
|
|
98
|
+
- Use read-only GITHUB_TOKEN permissions for untrusted events.
|
|
99
|
+
- Require maintainer approval before running the agent.
|
|
100
|
+
- Sanitize and summarize untrusted content before passing it to an agent.
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Suppressing Findings
|
|
104
|
+
|
|
105
|
+
Real workflows sometimes have a finding you've reviewed and accepted. Two ways to silence one without disabling the whole scan:
|
|
106
|
+
|
|
107
|
+
**Inline (per file)** — add a comment anywhere in the workflow:
|
|
108
|
+
|
|
109
|
+
```yaml
|
|
110
|
+
# agentci-ignore agentci/unpinned-ai-action -- mirrored internally, reviewed 2026-06
|
|
111
|
+
# agentci-ignore-all -- silence every rule in this file
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
**Config file** — `agentci.config.json` in the scanned path (or pass `--config <path>`):
|
|
115
|
+
|
|
116
|
+
```json
|
|
117
|
+
{
|
|
118
|
+
"ignore": ["agentci/unpinned-ai-action"],
|
|
119
|
+
"ignorePaths": ["**/generated-*.yml"]
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
`ignore` suppresses a rule everywhere; `ignorePaths` excludes matching workflow files (`*` within a path segment, `**` across segments). Ignored files are still parsed — they just don't report findings.
|
|
124
|
+
|
|
125
|
+
## Development
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
corepack enable
|
|
129
|
+
pnpm install
|
|
130
|
+
pnpm typecheck
|
|
131
|
+
pnpm test
|
|
132
|
+
pnpm build
|
|
133
|
+
npm pack --dry-run
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
## Security Boundary
|
|
137
|
+
|
|
138
|
+
AgentCI Guard is a static scanner. It does not sandbox workflows or prove that an agent is safe. It identifies high-risk patterns that should receive human review before AI agents are allowed to run with privileged CI/CD context.
|
|
139
|
+
|
|
140
|
+
See [Threat Model](docs/threat-model.md) and [Real-World Findings](docs/real-world-findings.md) (a scan of 75 public repos that run AI agents in CI).
|
|
141
|
+
|
|
142
|
+
## License
|
|
143
|
+
|
|
144
|
+
MIT
|
package/SECURITY.md
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
AgentCI Guard is security-sensitive CI/CD tooling. Do not publish exploit details for unfixed vulnerabilities in public issues.
|
|
4
|
+
|
|
5
|
+
## Supported Versions
|
|
6
|
+
|
|
7
|
+
During the `0.x` phase, only the latest `main` branch and latest published package are supported.
|
|
8
|
+
|
|
9
|
+
## Reporting a Vulnerability
|
|
10
|
+
|
|
11
|
+
Use GitHub Security Advisories when available. If private reporting is unavailable, open a minimal public issue asking for a disclosure channel without including exploit details.
|
|
12
|
+
|
|
13
|
+
A useful report includes:
|
|
14
|
+
|
|
15
|
+
- AgentCI Guard version or commit
|
|
16
|
+
- Workflow YAML that reproduces the issue, with secrets removed
|
|
17
|
+
- Expected finding
|
|
18
|
+
- Actual finding
|
|
19
|
+
- Whether the issue is false negative, false positive, crash, or SARIF/report problem
|
|
20
|
+
|
|
21
|
+
## Non-Goals
|
|
22
|
+
|
|
23
|
+
AgentCI Guard does not execute or sandbox workflows. A static scan passing does not certify an AI-agent workflow as safe.
|
package/action.yml
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
name: AgentCI Guard
|
|
2
|
+
description: Scan GitHub Actions workflows for unsafe AI coding-agent usage.
|
|
3
|
+
author: David Wu
|
|
4
|
+
branding:
|
|
5
|
+
icon: shield
|
|
6
|
+
color: red
|
|
7
|
+
inputs:
|
|
8
|
+
path:
|
|
9
|
+
description: Repository path to scan.
|
|
10
|
+
required: false
|
|
11
|
+
default: "."
|
|
12
|
+
sarif:
|
|
13
|
+
description: SARIF output path.
|
|
14
|
+
required: false
|
|
15
|
+
default: "agentci-results.sarif"
|
|
16
|
+
fail-on:
|
|
17
|
+
description: Minimum severity that fails the action. One of none, low, medium, high, critical.
|
|
18
|
+
required: false
|
|
19
|
+
default: "high"
|
|
20
|
+
outputs:
|
|
21
|
+
findings:
|
|
22
|
+
description: Total number of findings.
|
|
23
|
+
critical:
|
|
24
|
+
description: Number of critical-severity findings.
|
|
25
|
+
high:
|
|
26
|
+
description: Number of high-severity findings.
|
|
27
|
+
medium:
|
|
28
|
+
description: Number of medium-severity findings.
|
|
29
|
+
low:
|
|
30
|
+
description: Number of low-severity findings.
|
|
31
|
+
sarif-path:
|
|
32
|
+
description: Path to the written SARIF file.
|
|
33
|
+
runs:
|
|
34
|
+
using: node24
|
|
35
|
+
main: dist/cli.js
|
|
36
|
+
args:
|
|
37
|
+
- scan
|
|
38
|
+
- ${{ inputs.path }}
|
|
39
|
+
- --sarif
|
|
40
|
+
- ${{ inputs.sarif }}
|
|
41
|
+
- --fail-on
|
|
42
|
+
- ${{ inputs.fail-on }}
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|