AppSec Rules Pack
A versioned AppSec rules pack and the validator that keeps it honest. Each rule states
what to review, what evidence proves it, how to fix it, and how long an exception may
last, with mappings to OWASP ASVS 5.0, the OWASP API Security Top 10, OWASP Top 10:2025,
CWE, and NIST SSDF. The appsec-rules CLI validates packs against a JSON Schema contract
and semantic checks, so a pack can serve as a CI quality gate and as review evidence.
The demo is real CLI output. Recreate it from a source
checkout with python docs/assets/record-cli-demo.py.
Contents
- Scope
- Quick start
- Installation
- Verify a release
- CLI reference
- Writing a rules pack
- Use it in CI
- Optional executable Semgrep rules
- Project layout
- Documentation
- Contributing, security, and license
Scope
| It does | It does not |
|---|---|
| Define a JSON Schema contract for AppSec review rules | Scan application code or execute rules |
| Ship a generic baseline of 19 rules, each with a compliant and a violating example | Claim compliance: mappings are review aids, not conformance |
| Validate packs: schema, duplicate IDs, exception windows and policy, mapping formats, rule lifecycle, sensitive values | Embed enforcement: CI consumes the JSON report and decides (ADR-0004) |
| Derive a rule index, a Semgrep metadata scaffold, a SARIF rule catalog, and a mapping coverage report | Turn the derived scaffold into detections: its patterns are placeholders (ADR-0001) |
The baseline covers authentication, authorization, input validation, injection and XSS, SSRF, secrets, file handling, logging, dependency risk, configuration, session hardening, CSRF, webhook integrity, excessive data exposure, mass assignment, open redirect, and rate limiting. It contains no product names, tenant identifiers, customer data, secrets, or environment-specific configuration.
Mapping coverage of the baseline: ASVS 5.0, API Top 10 2023, CWE, and NIST SSDF on 19 of 19 rules; the optional OWASP Top 10:2025 field on 18 of 19.
Quick start
pip install "appsec-rules-pack==0.4.1"
curl -LO https://github.com/lucashgrifoni/AppSec-Rules-Pack/releases/download/v0.4.1/appsec-baseline.yaml
appsec-rules validate appsec-baseline.yaml --require-examples --fail-on-warnings
Expected output: Validation passed: 1 file, 19 rules, 0 errors, 0 warnings.
Installation
pip install appsec-rules-pack
This installs the appsec-rules console script and requires Python 3.12 or newer. Pin a
reviewed version, such as appsec-rules-pack==0.4.1, when the CLI runs as a quality gate.
The distribution contains the validator, the CLI, and the JSON Schema. It does not contain
a rules pack. Take the baseline from the assets of the
release you pin, copy
rules/appsec-baseline.yaml, or write your own pack.
To work from source:
python -m venv .venv
.venv/bin/python -m pip install -e ".[dev]" # Windows: .venv\Scripts\python
Verify a release
Every release is built and published by
publish-pypi.yml through PyPI Trusted Publishing,
with no long-lived token. Each GitHub Release carries the wheel, the sdist, a CycloneDX SBOM
(sbom.cdx.json), the baseline pack, and, from v0.4.0, the signed provenance bundle
(appsec-rules-pack-<tag>.intoto.jsonl). The wheel, sdist, SBOM, and baseline pack carry a
SLSA build-provenance attestation.
Verify a downloaded asset with a current GitHub CLI:
gh attestation verify appsec-baseline.yaml \
--repo lucashgrifoni/AppSec-Rules-Pack \
--signer-workflow lucashgrifoni/AppSec-Rules-Pack/.github/workflows/publish-pypi.yml \
--source-ref refs/tags/v0.4.1
Or offline, against the bundle attached to the release:
gh attestation verify appsec-baseline.yaml \
--repo lucashgrifoni/AppSec-Rules-Pack \
--bundle appsec-rules-pack-v0.4.1.intoto.jsonl
The same commands work for the wheel, the sdist, and sbom.cdx.json. A passing check proves
the artifact came from this repository's release workflow at that tag. It does not prove the
rule guidance is complete or that an application is secure. Treat a failed or unavailable
check as unverified provenance. ADR-0003 explains the
release design.
CLI reference
| Command | Purpose |
|---|---|
appsec-rules validate <file-or-dir> |
Validate one pack or every .yaml/.yml pack in a directory |
appsec-rules export index <pack> [-o file] |
Derive a machine-readable rule index (JSON) |
appsec-rules export semgrep <pack> [-o file] |
Derive a Semgrep scaffold with rule metadata and placeholder patterns |
appsec-rules export sarif <pack> [-o file] |
Derive a SARIF 2.1.0 rule catalog with an empty results array |
appsec-rules report coverage <pack> [-f json] [-o file] |
Count framework mappings per rule and AppSec category |
appsec-rules --version |
Print the installed version |
validate options:
| Option | Effect |
|---|---|
--fail-on-warnings |
Exit non-zero on warnings as well as errors |
--require-examples |
Warn when an enabled rule has no compliant/violating example |
--format json |
Emit a JSON report for CI |
The JSON report has a summary object (files, rules, errors, warnings, ok) and a
files array of per-file issues (level, path, message). Validation exits 0 on a
passing pack, 1 on a failing one, and 2 on a usage error such as a missing path.
The export and coverage commands only derive metadata; they do not validate first. Run
validate --require-examples --fail-on-warnings as the gate. From a source checkout,
python -m appsec_rules_pack works in place of appsec-rules.
Writing a rules pack
A pack is a pack block plus one or more rules. This minimal pack is complete and valid:
copy it, validate it, and grow it. Every field shown is required. The full contract is
appsec-rule.schema.json, and the
19 rules in rules/appsec-baseline.yaml are worked examples.
pack:
id: my-pack
name: My Rules Pack
version: 0.1.0
mode: advisory
owner: appsec
description: A minimal rules pack to start from.
rules:
- id: APPSEC-EXAMPLE-001
title: Require controlled error handling
description: Verify that invalid user input returns controlled errors without stack traces.
severity: medium
category: configuration
status: enabled
enforcement: advisory
targets:
- api
mappings:
owasp_asvs:
- V14.4
owasp_api_top_10_2023:
- API8:2023
cwe:
- CWE-209
nist_ssdf:
- PW.7
evidence:
required:
- Error handling path returns a documented response shape.
signals:
- Negative tests assert controlled error messages for invalid input.
match:
type: review
includes:
- API handlers that process untrusted input.
excludes:
- Local developer-only scripts that are not shipped.
remediation:
guidance: Replace raw exception output with a controlled error contract.
validation:
- Run negative tests for invalid input and malformed requests.
exceptions:
allowed: true
max_days: 30
required_fields:
- owner
- justification
- expires_at
Shapes that are easy to get wrong: evidence and match are objects, not lists;
remediation needs guidance; required_fields accepts only owner, justification,
expires_at, compensating_control, and validation_plan.
Rules are advisory by default. Each one carries a stable ID and severity, a target surface
and category, framework mappings, expected evidence and review signals, match guidance,
remediation and validation steps, exception requirements, a lifecycle status
(deprecated rules carry a deprecation block), and a compliant and a violating example.
CONTRIBUTING.md describes the severity model and the topic-based
mapping convention.
Use it in CI
examples/README.mdhas a GitHub Actions job that installs a pinned release and runs the strict JSON gate.examples/validation_gate.pyis a stdlib-only gate for any other CI system. It passes only when the CLI exits0and the report saysok: true..github/workflows/policy-gate.ymlis this repository's reference gate that consumes the JSON report.
Optional executable Semgrep rules
exports/semgrep-rules/ holds two hand-maintained,
tested Semgrep rules, kept separate from the validator
(ADR-0005):
| Baseline rule | Detection |
|---|---|
APPSEC-INJECT-001 |
Flask query/form values reaching SQL arguments on locally created sqlite3 connections and cursors |
APPSEC-SSRF-001 |
Flask query/form values reaching the URL argument of module-level Requests calls |
The other 17 baseline rules have no executable detection, and these two cover only their documented source and sink combinations. The layer README lists the known false positives and false negatives. Run the fixture suite with a separately installed engine:
python -m pip install "semgrep==1.179.0"
semgrep --test --strict --metrics=off --config exports/semgrep-rules/rules exports/semgrep-rules/tests
The appsec-rules CLI never invokes Semgrep, and export semgrep still emits only the
metadata scaffold.
Project layout
.github/ CI, security, policy-gate, Scorecard, Pages, and release workflows
docs/adr/ Architecture decision records
docs/assets/ CLI demo and social preview
examples/ CI integration examples
exports/ Derived artifacts and the optional executable Semgrep rules
rules/ The baseline rules pack
site/ Source of the project landing page
src/appsec_rules_pack/
Validator, CLI, exporters, and the JSON Schema
tests/ Test suite and pass, fail, and warning fixtures
Documentation
| Document | Contents |
|---|---|
CHANGELOG.md |
Changes per release |
STATUS.md |
Current state, dated verification results, risks and limits |
ROADMAP.md |
What shipped and what comes next |
TECHNICAL_SPEC.md |
Rule contract and validation design |
docs/adr/ |
Architecture decisions |
Contributing, security, and license
Contributions are welcome. Read CONTRIBUTING.md for rule authoring
principles, the severity and exception models, and the required checks:
python -m ruff check .
python -m pytest --cov=appsec_rules_pack --cov-report=term-missing
python -m appsec_rules_pack validate rules --require-examples --fail-on-warnings
python -m build
Participation follows the Code of Conduct. Report vulnerabilities
privately as described in SECURITY.md; do not open a public issue.
Licensed under the Apache License 2.0.
Metadata
Release files for appsec-rules-pack 0.4.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| appsec_rules_pack-0.4.1.tar.gz | 30.2 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| appsec_rules_pack-0.4.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 58.6 kB
Release files / appsec_rules_pack-0.4.1.tar.gz
| Download URL | appsec_rules_pack-0.4.1.tar.gz |
|---|---|
| Size | 30.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
66290099767390bb4a011c75ebcc8a62f360da6e91796d6a659115be03718440
|
|
BLAKE2b-256 checksum How to use checksums |
a43a1057d1dfd99c8eb57880f10c360f0c426412c03f7dc86839dcb3771b0724
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.
Transparency logRelease files / appsec_rules_pack-0.4.1-py3-none-any.whl
| Download URL | appsec_rules_pack-0.4.1-py3-none-any.whl |
|---|---|
| Size | 28.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
c86ea4f3c0e782a1b9581a8bf1225e16d8ae52958cb99edbaf8a80cc3c67d638
|
|
BLAKE2b-256 checksum How to use checksums |
95b3b8bd3ad5c158d833c6288733b168e4275232da25e3abc5c642ae64d8781e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Oct 5, 2026.
Transparency log