Skip to content

Commit e681af2

Browse files
Haiyue ZhangHaiyue Zhang
authored andcommitted
feat: taint tracking, CWE mapping, benchmark harness v2, and scanner enhancements
- Add TaintTracker for intra-function data flow analysis (AGENT-034 precision) - Add suppression model for baseline/fingerprint-based finding management - Enhance python_scanner with taint-aware tool input validation - Enhance mcp_config_scanner with new MCP security rules - Improve semantic_analyzer with framework-aware credential filtering - Upgrade SARIF formatter with CWE URI support and severity mapping - Add tier-to-severity mapping and rule-specific severity overrides - Expand ASI coverage rules (asi_coverage_v030.yaml) - Add new MCP security rules (mcp_security_v030.yaml) - Update benchmark oracle datasets and harness adapter for v2 eval - Add oracle_eval improvements for partial matching and scoring - Add GitHub Action (action.yml) enhancements - Add docs: README, security analysis spec, blog posts, evaluation report - Add example outputs and test fixtures - Add test_taint_tracker, test_baseline, test_cwe_mapping, test_formatters
1 parent abbeb3f commit e681af2

50 files changed

Lines changed: 8508 additions & 208 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/ISSUE_TEMPLATE/config.yml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
blank_issues_enabled: false
22
contact_links:
3-
- name: Questions & Discussions
3+
- name: General Question
44
url: https://github.com/HeadyZhang/agent-audit/discussions
5-
about: Ask questions and discuss ideas in GitHub Discussions
6-
- name: Documentation
5+
about: Ask general questions in GitHub Discussions
6+
- name: Rule Documentation
77
url: https://github.com/HeadyZhang/agent-audit/blob/main/docs/RULES.md
88
about: Check the rule reference for detailed information about each rule
9+
- name: OWASP Agentic Top 10
10+
url: https://genai.owasp.org/llm-top-10/
11+
about: Learn about the OWASP Agentic Top 10 vulnerabilities

PROMPT-v0.14.0-adjustment.txt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
数据很漂亮,但有一个需要诚实面对的问题
2+
3+
先说好的:Recall 68.2%、Precision 83.3%、F1 75.0%、Taint Accuracy 31.8%——从 v0.4.1 baseline 一路走来,这是实质性的进步。三个版本的轨迹非常健康:
4+
5+
Recall Precision Taint Acc
6+
7+
v0.4.1 17.6% - 0.0%
8+
9+
v0.13.0 50.0% 78.6% 9.1%
10+
11+
v0.14.0 68.2% 83.3% 31.8%
12+
13+
Precision 在 Recall 提升的同时还涨了 4.7pp,说明不是靠"什么都报"来刷 Recall。
14+
15+
但第 3 和第 4 点改动需要警惕
16+
17+
Fixed oracle line numbers in KNOWN-001, KNOWN-002, KNOWN-005
18+
19+
Added source type equivalence in oracle_eval.py: user_input ≈ llm_output
20+
21+
这两项改的不是检测引擎,而是benchmark 本身。
22+
23+
Oracle 行号修正如果确实是 oracle 写错了,那没问题——benchmark 本身也需要 debug。但需要确认:是 oracle 的行号原本就标错了,还是因为检测引擎报的行号和 oracle 不一致所以去改 oracle 来迁就?如果是后者,就是在拟合评测集。
24+
25+
user_input ≈ llm_output 等价性更微妙。从安全语义上说,这个等价有一定道理——两者都是不可信外部输入。但这个变更让 oracle 评估变得更宽松了,Taint Accuracy 从 9.1% 跳到 31.8% 有多少是因为检测能力提升、多少是因为评估标准放松?
26+
27+
建议:在 benchmark 报告中分离两个数字:
28+
29+
Strict Taint Accuracy(原始 oracle,不做等价映射)
30+
31+
Relaxed Taint Accuracy(含 source type 等价)
32+
33+
这样每个版本的改进中,工具能力提升和评估标准调整的贡献是透明的。这不是说等价映射不合理,而是作为学术级 benchmark 需要这种可追溯性。
34+
35+
Sink type mapping 修复是纯正的改进
36+
37+
eval() → code_execution 而不是 eval——这是检测引擎的输出和 oracle 术语的对齐,是合理的 normalization,不存在拟合问题。Source type 在 method call chain 中的传播保持也是 taint tracker 的实质性能力增强。
38+
39+
两个关键追问:
40+
41+
KNOWN-001 和 KNOWN-002 现在能检出了吗? 上个版本它们还是 0% Recall,这次你改了它们的 oracle 行号,但没明确说检测结果是否翻转。
42+
43+
Set B(MCP)和 Set C(Data)的分类 Recall 是多少? 整体 Recall 68.2% 可能掩盖了 Set B 仍然为 0% 的问题——这在 context 文档中被标为 P0。
44+
45+
总结
46+
47+
v0.14.0 的核心技术改进(sink mapping、source propagation)是扎实的。但 benchmark 侧的修改(oracle 行号、source 等价性)引入了评估标准的变化,需要用 strict/relaxed 双指标来保持透明度。下一步应该聚焦 Recall 最后的 12pp gap,优先确认 Set B/C 的分类表现和 KNOWN-001/002 的检出状态。

action.yml

Lines changed: 82 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,33 @@ inputs:
3535
default: 'true'
3636

3737
outputs:
38+
total_findings:
39+
description: 'Total number of security findings detected'
40+
value: ${{ steps.scan.outputs.total_findings }}
41+
critical_count:
42+
description: 'Number of CRITICAL severity findings (security-severity >= 9.0)'
43+
value: ${{ steps.scan.outputs.critical_count }}
44+
high_count:
45+
description: 'Number of HIGH severity findings (security-severity >= 7.0, < 9.0)'
46+
value: ${{ steps.scan.outputs.high_count }}
47+
medium_count:
48+
description: 'Number of MEDIUM severity findings (security-severity >= 4.0, < 7.0)'
49+
value: ${{ steps.scan.outputs.medium_count }}
50+
low_count:
51+
description: 'Number of LOW severity findings (security-severity < 4.0)'
52+
value: ${{ steps.scan.outputs.low_count }}
53+
scan_status:
54+
description: 'Scan status: success (exit code 0) or failure (findings exceed fail-on threshold)'
55+
value: ${{ steps.scan.outputs.scan_status }}
56+
sarif_file:
57+
description: 'Path to the generated SARIF file (if format=sarif)'
58+
value: ${{ steps.scan.outputs.sarif_file }}
3859
findings-count:
39-
description: 'Total number of findings'
40-
value: ${{ steps.scan.outputs.findings }}
60+
description: 'Total number of findings (deprecated: use total_findings)'
61+
value: ${{ steps.scan.outputs.total_findings }}
4162
exit-code:
42-
description: 'Exit code from the scan (0 = pass, 1 = fail)'
43-
value: ${{ steps.scan.outputs.exit-code }}
63+
description: 'Exit code from scan (deprecated: use scan_status)'
64+
value: ${{ steps.scan.outputs.exit_code }}
4465

4566
runs:
4667
using: 'composite'
@@ -64,8 +85,9 @@ runs:
6485
ARGS="${{ inputs.path }}"
6586
ARGS="$ARGS --format ${{ inputs.format }}"
6687
67-
if [ "${{ inputs.format }}" == "sarif" ] || [ -n "${{ inputs.output }}" ]; then
68-
ARGS="$ARGS --output ${{ inputs.output }}"
88+
OUTPUT_FILE="${{ inputs.output }}"
89+
if [ "${{ inputs.format }}" == "sarif" ] || [ -n "$OUTPUT_FILE" ]; then
90+
ARGS="$ARGS --output $OUTPUT_FILE"
6991
fi
7092
7193
ARGS="$ARGS --severity ${{ inputs.severity }}"
@@ -78,14 +100,62 @@ runs:
78100
agent-audit scan $ARGS
79101
EXIT_CODE=$?
80102
81-
echo "exit-code=$EXIT_CODE" >> $GITHUB_OUTPUT
103+
# Set exit code and scan status
104+
echo "exit_code=$EXIT_CODE" >> $GITHUB_OUTPUT
105+
if [ $EXIT_CODE -eq 0 ]; then
106+
echo "scan_status=success" >> $GITHUB_OUTPUT
107+
else
108+
echo "scan_status=failure" >> $GITHUB_OUTPUT
109+
fi
110+
111+
# Parse SARIF file to extract structured counts
112+
if [ -f "$OUTPUT_FILE" ]; then
113+
echo "sarif_file=$OUTPUT_FILE" >> $GITHUB_OUTPUT
114+
115+
# Total findings count
116+
TOTAL=$(jq '.runs[0].results | length' "$OUTPUT_FILE" 2>/dev/null || echo "0")
117+
echo "total_findings=$TOTAL" >> $GITHUB_OUTPUT
118+
119+
# Count findings by severity using rule security-severity scores
120+
# CVSS-aligned thresholds: Critical>=9.0, High>=7.0, Medium>=4.0, Low<4.0
121+
COUNTS=$(jq -r '
122+
# Build a map of ruleId -> security-severity score
123+
(
124+
[.runs[0].tool.driver.rules[]? |
125+
{key: .id, value: ((.properties."security-severity" // "0") | tonumber)}
126+
] | from_entries
127+
) as $sev_map |
128+
129+
# Count results by severity category
130+
reduce (.runs[0].results[]?) as $r (
131+
{critical: 0, high: 0, medium: 0, low: 0};
132+
($sev_map[$r.ruleId] // 0) as $score |
133+
if $score >= 9 then .critical += 1
134+
elif $score >= 7 then .high += 1
135+
elif $score >= 4 then .medium += 1
136+
else .low += 1
137+
end
138+
) |
139+
"critical_count=\(.critical)\nhigh_count=\(.high)\nmedium_count=\(.medium)\nlow_count=\(.low)"
140+
' "$OUTPUT_FILE" 2>/dev/null)
82141
83-
# Count findings from SARIF if available
84-
if [ -f "${{ inputs.output }}" ]; then
85-
FINDINGS=$(jq '.runs[0].results | length' "${{ inputs.output }}" 2>/dev/null || echo "0")
86-
echo "findings=$FINDINGS" >> $GITHUB_OUTPUT
142+
if [ -n "$COUNTS" ]; then
143+
echo "$COUNTS" >> $GITHUB_OUTPUT
144+
else
145+
# Fallback if jq parsing fails
146+
echo "critical_count=0" >> $GITHUB_OUTPUT
147+
echo "high_count=0" >> $GITHUB_OUTPUT
148+
echo "medium_count=0" >> $GITHUB_OUTPUT
149+
echo "low_count=0" >> $GITHUB_OUTPUT
150+
fi
87151
else
88-
echo "findings=0" >> $GITHUB_OUTPUT
152+
# No SARIF file - set all counts to 0
153+
echo "sarif_file=" >> $GITHUB_OUTPUT
154+
echo "total_findings=0" >> $GITHUB_OUTPUT
155+
echo "critical_count=0" >> $GITHUB_OUTPUT
156+
echo "high_count=0" >> $GITHUB_OUTPUT
157+
echo "medium_count=0" >> $GITHUB_OUTPUT
158+
echo "low_count=0" >> $GITHUB_OUTPUT
89159
fi
90160
91161
exit $EXIT_CODE

docs/README.md

Lines changed: 199 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,199 @@
1+
# Agent Audit Documentation
2+
3+
> **Version:** v0.15.1
4+
> **CLI static analysis tool for AI agent security — "ESLint for AI agents"**
5+
6+
---
7+
8+
## For Users
9+
10+
| Document | Description |
11+
|----------|-------------|
12+
| [Rule Reference](RULES.md) | Complete list of 40+ detection rules with OWASP mapping |
13+
| [CI/CD Integration](CI-INTEGRATION.md) | GitHub Actions, GitLab CI, Jenkins, Azure DevOps setup |
14+
| [API Stability](STABILITY.md) | Public interface stability guarantees |
15+
16+
### Quick Start
17+
18+
```bash
19+
# Install
20+
pip install agent-audit
21+
22+
# Scan your project
23+
agent-audit scan ./my-agent-project
24+
25+
# Output SARIF for GitHub Code Scanning
26+
agent-audit scan . --format sarif --output results.sarif
27+
```
28+
29+
---
30+
31+
## For Contributors
32+
33+
| Document | Description |
34+
|----------|-------------|
35+
| [Architecture](ARCHITECTURE.md) | System design, module dependencies, extension points |
36+
| [Contributing](../CONTRIBUTING.md) | How to contribute rules, scanners, and fixes |
37+
38+
### Development Setup
39+
40+
```bash
41+
cd packages/audit
42+
poetry install
43+
poetry run pytest ../../tests/ -v
44+
```
45+
46+
---
47+
48+
## Architecture Overview
49+
50+
```
51+
┌──────────────────────────────────────────────────────────────────┐
52+
│ CLI Layer │
53+
│ scan.py │ inspect_cmd.py │ formatters/*.py │
54+
└──────────────────────────────────┬───────────────────────────────┘
55+
56+
┌──────────────────────────────────▼───────────────────────────────┐
57+
│ Scanner Layer │
58+
│ ┌────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │
59+
│ │ PythonScanner │ │ MCPConfigScanner│ │ SecretScanner │ │
60+
│ │ (AST-based) │ │ (JSON/YAML) │ │ (regex+semantic)│ │
61+
│ └────────────────┘ └─────────────────┘ └─────────────────┘ │
62+
└──────────────────────────────────┬───────────────────────────────┘
63+
64+
┌──────────────────────────────────▼───────────────────────────────┐
65+
│ Analysis Layer │
66+
│ ┌─────────────────┐ ┌─────────────────┐ ┌──────────────────┐ │
67+
│ │SemanticAnalyzer │ │ TaintTracker │ │FrameworkDetector │ │
68+
│ │ (3-stage cred) │ │ (data flow) │ │ (FP reduction) │ │
69+
│ └─────────────────┘ └─────────────────┘ └──────────────────┘ │
70+
└──────────────────────────────────┬───────────────────────────────┘
71+
72+
┌──────────────────────────────────▼───────────────────────────────┐
73+
│ Rules Engine │
74+
│ engine.py + rules/builtin/*.yaml │
75+
└──────────────────────────────────┬───────────────────────────────┘
76+
77+
┌──────────────────────────────────▼───────────────────────────────┐
78+
│ Data Models │
79+
│ Finding │ Severity │ Location │ Category │
80+
└──────────────────────────────────────────────────────────────────┘
81+
```
82+
83+
---
84+
85+
## Scanners
86+
87+
### PythonScanner
88+
**Input:** `.py` files
89+
**Method:** Python AST parsing
90+
**Detects:**
91+
- Dangerous function calls (`eval`, `exec`, `subprocess.run(shell=True)`)
92+
- `@tool` decorated functions and their permissions
93+
- SQL injection via string interpolation
94+
- Framework-specific patterns (LangChain, CrewAI, AutoGen)
95+
96+
### SecretScanner
97+
**Input:** All text files
98+
**Method:** Regex patterns + Semantic analysis + Entropy calculation
99+
**Detects:**
100+
- Hardcoded API keys (AWS, OpenAI, Anthropic, etc.)
101+
- Database connection strings
102+
- Private keys and tokens
103+
104+
### MCPConfigScanner
105+
**Input:** `claude_desktop_config.json`, MCP YAML configs
106+
**Method:** JSON/YAML parsing + Policy validation
107+
**Detects:**
108+
- Overly broad filesystem access
109+
- Unverified MCP server sources
110+
- Sensitive environment variable exposure
111+
- Missing authentication
112+
113+
### PrivilegeScanner
114+
**Input:** Python files
115+
**Method:** AST pattern matching
116+
**Detects:**
117+
- Privilege escalation patterns
118+
- Unsandboxed subprocess execution
119+
- Credential store access
120+
121+
---
122+
123+
## Taint Analysis
124+
125+
The `TaintTracker` module performs intra-procedural data flow analysis:
126+
127+
### Components
128+
129+
1. **TaintSource** — Entry points (function parameters, `os.getenv()`, `request.json()`)
130+
2. **TaintSink** — Dangerous operations (`subprocess.run`, `eval`, `cursor.execute`)
131+
3. **TaintFlow** — Tracks data propagation through assignments and operations
132+
4. **Sanitization Detection** — Identifies validation/sanitization nodes
133+
134+
### Strategy
135+
136+
- **Conservative:** If uncertain, assume tainted (minimize false negatives)
137+
- **Intra-procedural:** Analysis within single functions (no cross-function tracking yet)
138+
- **Contextual:** Adjusts confidence based on decorator context (`@tool` = higher confidence)
139+
140+
---
141+
142+
## Confidence Scoring
143+
144+
All findings include a confidence score (0.0-1.0) and are assigned to tiers:
145+
146+
| Tier | Confidence | Action |
147+
|------|------------|--------|
148+
| **BLOCK** | >= 0.90 | Fix immediately — very high confidence |
149+
| **WARN** | >= 0.60 | Should fix — high confidence |
150+
| **INFO** | >= 0.30 | Review recommended |
151+
| **SUPPRESSED** | < 0.30 | Likely false positive — auto-suppressed |
152+
153+
### Confidence Factors
154+
155+
- **Context:** Tool decorator (+), class method (neutral), standalone function (-)
156+
- **Value analysis:** High entropy (+), placeholder patterns (-)
157+
- **Framework detection:** Pydantic Field definitions (-), LangChain internals (-)
158+
- **File path:** Test files (-), example code (-)
159+
160+
---
161+
162+
## Limitations
163+
164+
1. **Intra-procedural only** — Taint analysis does not track data flow across functions or files
165+
2. **Python only** — TypeScript/JavaScript MCP servers require separate tooling
166+
3. **Static analysis** — Cannot detect runtime-only vulnerabilities
167+
4. **Pattern-based** — Novel attack patterns may not be detected until rules are added
168+
5. **No symbolic execution** — Cannot reason about complex conditional logic
169+
170+
---
171+
172+
## Technical Specifications
173+
174+
For detailed technical specifications (internal use):
175+
176+
- [Security Analysis Specification](SECURITY-ANALYSIS-SPECIFICATION.md) — Detection methodology and threat mapping
177+
- [specs/technical-spec.md](../specs/technical-spec.md) — Full system architecture and implementation details
178+
- [specs/delta-spec.md](../specs/delta-spec.md) — Design decisions and refinements
179+
180+
---
181+
182+
## OWASP Agentic Top 10 Coverage
183+
184+
Agent Audit covers all 10 categories of the [OWASP Agentic Top 10 (2026)](https://genai.owasp.org/):
185+
186+
| ASI | Category | Rules |
187+
|-----|----------|-------|
188+
| ASI-01 | Agent Goal Hijacking | AGENT-010, 011, 027, 050 |
189+
| ASI-02 | Tool Misuse | AGENT-001, 026, 029, 032, 034-036, 040, 041 |
190+
| ASI-03 | Privilege Abuse | AGENT-002, 013, 014, 042 |
191+
| ASI-04 | Supply Chain | AGENT-004, 005, 015, 016, 030 |
192+
| ASI-05 | Code Execution | AGENT-003, 017, 031 |
193+
| ASI-06 | Memory Poisoning | AGENT-018, 019 |
194+
| ASI-07 | Inter-Agent Comms | AGENT-020 |
195+
| ASI-08 | Cascading Failures | AGENT-021, 022, 028 |
196+
| ASI-09 | Trust Exploitation | AGENT-023, 033, 037-039, 052 |
197+
| ASI-10 | Rogue Agents | AGENT-024, 025, 053 |
198+
199+
**Coverage: 10/10 ASI categories, 40+ rules**

0 commit comments

Comments
 (0)