Skip to content
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b22bf57
Fix scoring/runner correctness bugs and reconcile inflated claims
claude Jun 3, 2026
677b826
Complete verdict wiring, fix silent-timeout false negative, fix serve…
claude Jun 3, 2026
b60d1e3
Fix silent detection-pattern loss from duplicate YAML keys; harden lo…
claude Jun 3, 2026
abe40fc
Enterprise hardening: SSRF guard, otel loopback bind, py.typed, drop …
claude Jun 3, 2026
c470ab3
Docs/metadata correctness + path-traversal guard; untrack generated s…
claude Jun 3, 2026
217199b
Fix openai-agents dependency, citation date, and JS/RFC package refs
claude Jun 3, 2026
d6d876b
Remove internal go-to-market and strategy docs from the public repo
claude Jun 3, 2026
74e4bd0
Make 'aastf benchmark run' fail honestly; fix the shipped benchmark c…
claude Jun 3, 2026
dc98ebe
REFUSAL_ECHO now verifies the payload was actually echoed
claude Jun 3, 2026
d4e990d
Route MCP and multi-agent scenarios to their evaluators (were dead code)
claude Jun 3, 2026
b29f1a5
Harden release/CI: single gated PyPI path, npm lockfile, fix eslint peer
claude Jun 3, 2026
3be8557
Fix adapter capture gaps: langgraph double-count and dead iteration_c…
claude Jun 3, 2026
883d715
chore: add enterprise engineering-hygiene foundations
claude Jun 3, 2026
ace5368
Add pre-commit config (ruff + standard hooks)
claude Jun 3, 2026
34ea2bb
docs: align claims with reality, mark experimental surfaces
claude Jun 3, 2026
01e0c80
Merge ws/docs: honest capability matrix, experimental markers, doc re…
claude Jun 3, 2026
9177940
Deepen adapters: real generic adapter + harden crewai/openai/pydantic
claude Jun 3, 2026
eb69118
Merge ws/adapters: real generic adapter, hardened instrumentation, de…
claude Jun 3, 2026
7638532
Add evasion-resistant normalization layer for detection
claude Jun 3, 2026
527c23b
Merge ws/detection: unicode/encoding normalization + evasion suite
claude Jun 3, 2026
e67de4e
benchmark: add key-free deterministic provider + reproducible referen…
claude Jun 3, 2026
7b16a67
Merge ws/benchmark: pluggable providers + deterministic reproducible …
claude Jun 3, 2026
aa192c2
Reconcile test-count badge to actual collected count (2957)
claude Jun 3, 2026
0aa87bf
Make the codebase mypy-clean and promote type checking to a CI gate
claude Jun 3, 2026
1b1a2e7
Add CLI tests for the serve command (was untested)
claude Jun 3, 2026
b09cdf9
Fix CI: stop benchmark tests writing into the repo + ruff 0.8.6 lint
claude Jun 3, 2026
6add835
Fix CI: make serve-help test robust to Rich ANSI coloring
claude Jun 3, 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
27 changes: 27 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# EditorConfig — consistent formatting across editors.
# https://editorconfig.org
root = true

[*]
charset = utf-8
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
indent_style = space
indent_size = 4

[*.py]
indent_size = 4
max_line_length = 100

[*.{yml,yaml}]
indent_size = 2

[*.{json,toml}]
indent_size = 2

[*.md]
trim_trailing_whitespace = false

[Makefile]
indent_style = tab
82 changes: 82 additions & 0 deletions .github/ISSUE_TEMPLATE/bug_report.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
name: Bug Report
description: Report a defect in AASTF
title: "[Bug] Brief description of the problem"
labels: ["bug"]

body:
- type: markdown
attributes:
value: |
Thanks for taking the time to file a bug report. Please search existing
issues first to avoid duplicates.

- type: textarea
id: summary
attributes:
label: What happened?
description: A clear and concise description of the bug.
placeholder: "Running `aastf run ...` raises a ValidationError when the scenario uses tool_input_contains."
validations:
required: true

- type: textarea
id: expected
attributes:
label: Expected behavior
description: What did you expect to happen instead?
validations:
required: true

- type: textarea
id: repro
attributes:
label: Steps to reproduce
description: Minimal steps (and commands) to reproduce the behavior.
placeholder: |
1. Install with `pip install -e ".[dev]"`
2. Run `aastf scenario validate ...`
3. See error
render: shell
validations:
required: true

- type: textarea
id: logs
attributes:
label: Relevant logs / traceback
description: Paste any error output. This will be rendered as code.
render: shell

- type: input
id: aastf_version
attributes:
label: AASTF version
description: Output of `aastf --version` or the installed package version.
placeholder: "2.0.0"
validations:
required: true

- type: input
id: python_version
attributes:
label: Python version
description: Output of `python --version`.
placeholder: "3.12.4"
validations:
required: true

- type: input
id: os
attributes:
label: Operating system
placeholder: "Ubuntu 24.04 / macOS 14 / Windows 11"
validations:
required: true

- type: checkboxes
id: checklist
attributes:
label: Checklist
options:
- label: I have searched existing issues and this is not a duplicate
- label: I can reproduce this on the latest version
30 changes: 30 additions & 0 deletions .github/pull_request_template.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<!--
Thanks for contributing to AASTF! Please fill out the sections below.
Keep the title descriptive, e.g. "[Scenario] ASI02: S3 exfiltration via injected presigned URL".
-->

## Summary

<!-- What does this PR do and why? -->

## Type of change

- [ ] New attack scenario (YAML only)
- [ ] New payload variant for an existing scenario
- [ ] New / updated evaluator
- [ ] New / updated framework adapter
- [ ] Bug fix
- [ ] Documentation
- [ ] Tooling / CI / packaging

## Related issues

<!-- e.g. "Closes #123" -->

## Checklist

- [ ] `ruff check src/ tests/` passes
- [ ] `pytest tests/unit/ -v` passes
- [ ] Tests added/updated for new evaluators or adapters (scenarios are validated by schema)
- [ ] Docs updated if behavior or public interfaces changed
- [ ] No secrets, API keys, or proprietary content included
50 changes: 48 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,45 @@ jobs:
- run: pip install -e ".[dev,langgraph]"
- run: pytest tests/unit/ -v --tb=short

# Type checking — gating. The src tree is mypy-clean (with the langgraph
# extra installed), so type regressions now fail CI.
mypy:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- name: Harden runner
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
with:
egress-policy: audit

- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.12"
- run: pip install -e ".[dev,langgraph]"
- run: mypy

# Non-blocking coverage report. The blocking unit-test gate lives in the
# `test` job; this job adds visibility without coupling coverage to merges.
coverage:
runs-on: ubuntu-latest
continue-on-error: true
permissions:
contents: read
steps:
- name: Harden runner
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
with:
egress-policy: audit

- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 # v5.6.0
with:
python-version: "3.12"
- run: pip install -e ".[dev,langgraph]"
- run: pytest tests/unit/ --cov=aastf --cov-report=term-missing

scenario-validate:
runs-on: ubuntu-latest
permissions:
Expand All @@ -63,11 +102,18 @@ jobs:
python-version: "3.12"
- run: pip install -e ".[dev]"
- run: |
for f in src/aastf/scenarios/builtin/**/*.yaml; do
# `find` (not a `**` glob) so every nested scenario is validated —
# bash globstar is off by default, so `**/*.yaml` would silently
# match nothing and validate zero scenarios.
found=0
while IFS= read -r f; do
found=$((found + 1))
python -c "
from pathlib import Path
from aastf.scenarios.loader import load_scenario
s = load_scenario(Path('$f'))
print(f'VALID {s.id}: {s.name}')
"
done
done < <(find src/aastf/scenarios/builtin -name '*.yaml')
echo "Validated $found scenarios"
test "$found" -gt 0
4 changes: 2 additions & 2 deletions .github/workflows/publish-npm.yml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: Publish @aastf/core to npm
name: Publish asi-scan to npm

on:
push:
Expand Down Expand Up @@ -26,7 +26,7 @@ jobs:
registry-url: "https://registry.npmjs.org"

- name: Install dependencies
run: npm install --legacy-peer-deps
run: npm ci # reproducible install from the committed package-lock.json

- name: Build TypeScript
run: npm run build
Expand Down
30 changes: 0 additions & 30 deletions .github/workflows/publish.yml

This file was deleted.

32 changes: 27 additions & 5 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,34 @@ permissions:
contents: write
id-token: write # Required for Sigstore OIDC signing

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
test:
name: Test and lint
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4

- uses: actions/setup-python@v5
with:
python-version: "3.12"

- name: Install
run: |
pip install ruff==0.8.6
pip install -e ".[dev,langgraph]"

- name: Lint
run: ruff check src/ tests/

- name: Test
run: pytest tests/unit/ tests/self_audit/ tests/adversarial/ tests/contracts/ -q

build:
name: Build distribution
runs-on: ubuntu-latest
needs: test # never publish an untested/red build
permissions:
contents: read
steps:
Expand Down Expand Up @@ -70,8 +91,6 @@ jobs:
runs-on: ubuntu-latest
needs: sign
environment: pypi
permissions:
id-token: write # OIDC trusted publisher
steps:
- name: Download signed artifacts
uses: actions/download-artifact@v4
Expand All @@ -82,6 +101,9 @@ jobs:
- name: Publish to PyPI
uses: pypa/gh-action-pypi-publish@release/v1
with:
# Token-based publishing. (This is the single PyPI publish path; the
# former release-triggered OIDC workflow was removed to stop the two
# racing each other on every release.)
password: ${{ secrets.PYPI_API_TOKEN }}
skip-existing: true

Expand Down
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,4 +21,6 @@ benchmark/results/
htmlcov/
*.pdf
plan.md
node_modules/
node_modules/
# Generated MkDocs output — build in CI / GitHub Pages, do not commit
site/
18 changes: 18 additions & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Pre-commit hooks for AASTF. Install: pip install pre-commit && pre-commit install
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- id: check-toml
- id: check-added-large-files
- id: check-merge-conflict
- id: mixed-line-ending
- id: debug-statements
- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.8.6
hooks:
- id: ruff
args: [--fix]
2 changes: 1 addition & 1 deletion .zenodo.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
"autonomous agents",
"execution graph interception"
],
"description": "AASTF is an open-source Python framework for automated security testing of autonomous AI agent systems. It intercepts agent execution graphs at runtime, injects adversarial payloads, and evaluates agent behavior against the OWASP Top 10 for Agentic Applications (ASI) taxonomy. Ships with 50 attack scenarios, SARIF/JSON/HTML reporting, and a three-class verdict system (VULNERABLE, REFUSAL_ECHO, SAFE).",
"description": "AASTF is an open-source Python framework for automated security testing of autonomous AI agent systems. It intercepts agent execution graphs at runtime, injects adversarial payloads, and evaluates agent behavior against the OWASP Top 10 for Agentic Applications (ASI) taxonomy. Ships with 130+ attack scenarios (OWASP ASI, MCP, multi-agent, and CVE-derived packs), SARIF/JSON/HTML reporting, and a three-class verdict system (VULNERABLE, REFUSAL_ECHO, SAFE).",
"access_right": "open",
"related_identifiers": [
{
Expand Down
42 changes: 42 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,48 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

---

## [2.0.0] — 2026-06-03

This entry reconciles the changelog with the shipped package version (`pyproject.toml`
and `aastf.__version__` were already `2.0.0` while this file stopped at `0.4.1`).
It consolidates the changes accumulated across the 0.5.x–2.0.0 line.

### Added

- **Expanded scenario registry** — over 130 built-in scenarios covering the OWASP ASI
Top 10 plus MCP, multi-agent (MAS), agent-to-agent (A2A), and CVE-derived packs.
- **MCP security testing** — tool/schema/preference poisoning verdicts and evaluators.
- **AI-VSS scoring** and CycloneDX BOM export; EU AI Act, MITRE ATT&CK/ATLAS, and
CWE compliance mappings.
- HTML, SARIF, and JSON reporters wired into `aastf run` (HTML output now also
produced directly by `run`, not only `report show`).

### Fixed

- **Overall risk score is now monotonic.** The previous severity-weighted *average*
could *lower* the headline score as additional findings were discovered; risk is now
a cumulative ("noisy-OR") aggregation that never decreases when findings are added.
- **Multi-agent verdicts** (`INFECTION_PROPAGATED`, `COLLUSION`, `WATCHDOG_BYPASS`) are
counted as vulnerabilities and no longer raise a `KeyError` while building the ASI
summary or get silently mis-counted as inconclusive.
- Cascade detection thresholds of `0` ("any tool call / iteration fails") are now
honoured instead of being treated as "no limit".
- RCE output heuristic no longer false-positives on a single benign `uid=0` mention
(removed the redundant `uid=` substring pattern).
- REFUSAL_ECHO discount unified at 35% across both scoring engines (`scoring` and
`ai_vss`), which previously disagreed (35% vs 40%).
- Corrected the LangGraph checkpoint-deserialization CVE reference to **CVE-2025-64439**
(the JsonPlusSerializer RCE); CVE-2025-68664 is a separate LangChain Core flaw.

### Changed

- README claims reconciled with reality: test-count badge reflects the actual collected
count, Python badge corrected to 3.10+, headline attack-rate figure attributed to its
source (Agent Security Bench), and the scenario count corrected.
- npm package naming made consistent with the published name `asi-scan`.

---

## [0.4.1] — 2026-05-20

### Changed
Expand Down
Loading
Loading