Repository navigation
Releases: pennacle-security/cairnlock
Releases · pennacle-security/cairnlock
Release list
v0.8.0
Added
- Ancestor discovery:
cairnlock scan --include-ancestors. Agents merge
AGENTS.md and other context files from parent directories up the tree, so
one stray file above the project can steer a run. With the flag, every
parent directory up to the filesystem root is checked for context files
(non-recursive by design — recursive ancestor walks would sweep sibling
projects), and findings are reported with../paths so it is always
visible that they live outside the scanned tree. The MCPscantool
takes the same option. - New core rule TAM001: an agent context file that instructs the agent to
runcairnlock approve, delete or revert the lockfile, disable or bypass
the scanner, or addcairnlock:ignoresuppressions is asking the agent
to defeat the guard — reported at high (medium for weakening flags).
Ordinary documentation about the tool stays clean. Bad/good fixtures
included.
Fixed
- FSY001's path-traversal pattern matched
../anywhere, including
docstrings that merely explain relative paths. Traversal now requires a
quoted path string ("../x","../../y"), which is where it is real.
Changed
- Discovery internals:
scanner.scanacceptsinclude_ancestors, and the
CLI walks(path, relative)target pairs so project files and ancestor
files share one loop.
v0.7.0
Added
cairnlock mcp: an MCP stdio server that exposes scan, verify, rules,
and stats as agent-callable tools, so coding agents can audit their own
context files mid-session. Speaks newline-delimited JSON-RPC 2.0
(initialize, tools/list, tools/call, ping) with no new dependencies;
stdout carries protocol messages only.cairnlock scan --changed <git-ref>: scan only files changed since a
ref (plus untracked files). Turns scan from a whole-repo job into a
change-scoped one for monorepos and PR checks. Git is called with an
argument list; bad refs exit 2 with the usual messages.scan --format github: GitHub Actions workflow-command annotations
(::error file=...,line=...,title=...), with percent and newline
escaping so messages cannot inject extra annotations.cairnlock hook install|uninstall: writes and removes the pre-commit
hook in.git/hookswithout the manual copy. Refuses to touch a
pre-existing foreign hook; uninstall only removes hooks cairnlock
manages..pre-commit-hooks.yaml: cairnlock is now usable directly from the
pre-commit framework (repo: https://github.com/pennacle-security/cairnlock,
idscairnlock-verifyandcairnlock-scan).- New core rule CLD001: flags risky permission allowlists in Claude Code
settings.json— bareBash,Bash(curl:*)-style network and shell
entries, anddefaultMode: "bypassPermissions". Ships with bad/good
fixtures; ordinary entries likeBash(npm run test:*)stay clean. cairnlock rulesoutput includes the new rule; machine formats emit a
valid empty document when there is nothing to scan instead of silence.
Fixed
- The release workflow's GitHub Release job now downloads the dist
artifact before creating the release; previously it attached no files.
Added
- Documentation site is live at
https://pennacle-security.github.io/cairnlock/ (GitHub Pages from
/docs), linked from pyproject metadata and the README.
Changed
- Dependabot bumps: actions/checkout 4 → 7 and actions/setup-python
5 → 7 across the CI and release workflows and the composite action.
v0.6.0
Added
- Self-scan gate in CI: the repository runs
cairnlock scan --profile extended --fail-on highon itself and ships.cairnlockignoreso the
rule modules and test fixtures do not drown the signal. The scanner's own
subprocesscall carries an inlinecairnlock:ignore— the suppression
feature used where it belongs. - Self-scan regression test asserting zero high findings.
- Documentation site upgrade: shared
docs/styles.css, a new FAQ page
covering exit codes, false positives, adoption path, and lockfile
recovery, plus corrected version references in the CI examples. docs/social-kit.mdwith ready-to-post announcements and
assets/social-card.svgfor the repository social preview.
Fixed
--no-bannerafter a subcommand failed with exit 2 ("No such option"),
which brokecairnlock scan --no-bannerand the GitHub Action's scan
step for every user. The banner now prints lazily per command: JSON,
SARIF, HTML, and Markdown output never show it, and the option works
before or after the subcommand.- SHC001's f-string pattern matched every f-string call in any scanned
file (dozens of false positives on ordinary Python code, including
cairnlock's own CLI). The pattern is removed; real f-string shell
injection stays covered by the os.system and subprocess patterns, which
see the command context. - FSY001's
config.jsonpattern matched any filename containing it, such
asclaude_desktop_config.json. Word boundaries fix the match.
v0.5.0
Added
- Rule profiles, per the approved rules audit:
core(default): agent-specific rules on agent context files.extended: generic rules plus widened discovery for source files
(.py,.js,.ts) and dependency files (requirements*,
package.json,pyproject.toml,setup.py,setup.cfg).scan --profile {core,extended},profilekey incairnlock.tomland
[tool.cairnlock], and aprofileinput inaction.yml.- Profiles are exclusive; every rule id belongs to exactly one profile
and rule ids are unchanged.
- Anti-false-positive mechanisms:
- Inline suppression:
cairnlock:ignore(all rules) or
cairnlock:ignore RULE1,RULE2(selected rules) anywhere in a line. - All scans deduplicate findings with identical rule, path, line, and
message, so one issue yields one finding.
- Inline suppression:
- Anti-false-negative mechanisms:
- SUP001 reads requirements files line by line; bare requirement names
are flagged. The old pattern searched for the literal text
"requirements.txt" inside lines and never matched real files. - Extended-profile discovery brings code and dependency files to the
generic rules.
- SUP001 reads requirements files line by line; bare requirement names
- Tests for per-profile finding counts, cross-profile exclusivity,
duplicate detection, inline suppression, and discovery behavior.
Changed
- MCP003 now flags shell and infrastructure commands as the MCP server
executable (bash, sh, powershell, curl, wget, docker, podman, kubectl,
helm) and no longer duplicates UNP001 on package runners. UNP001 covers
npx, uvx, bunx, pnpm, yarn, and pipx, includingdlx/runsubcommands,
sopnpm dlx some-serverreportssome-serverinstead ofdlx. - OBF001 no longer scans skill files (REM001's scope); the duplicated
long-base64 finding is gone. - CFG001 no longer scans markdown and text files, and its hardcoded-secret
pattern was removed (SEC001 owns credentials); template prose no longer
triggers findings. - CRY001 hardcoded-key detection requires crypto-specific names
(secret_key,encryption_key,private_key,iv,nonce,salt);
plainkey =assignments no longer duplicate SEC001. cairnlock rulesshows a Profile column and per-rule scope.
v0.4.0
Added
- Noise controls for adoption on large repositories:
cairnlock.toml(or[tool.cairnlock]inpyproject.toml) with
ignoreglobs,disabled_rules, and afail_onthreshold..cairnlockignorewith gitignore-style globs.scan --fail-on {low,medium,high,never}: exit 1 only when a finding at
or above the threshold exists. Exposed as thefail-onaction input.scan --baseline <file>and--write-baseline: known finding
fingerprints are suppressed from reports and the exit decision.- The ASCII banner goes to stderr; JSON, SARIF, HTML, and Markdown output
on stdout stay parseable. Regression tests cover this with the banner on.
- Discovery for more agent ecosystems, each with a fixture and a test:
.github/copilot-instructions.md,GEMINI.md,.windsurfrules,
.clinerules(file or directory),.roo/**,.continue/**,
.cursor/mcp.json,.vscode/mcp.json,.gemini/settings.json,
claude_desktop_config.json. Hidden agent directories (.claude,
.opencode,.cursor,.roo,.continue,.gemini,.vscode,
.github) are scanned;.git,.venv, andnode_modulesstay ignored.
Fixes a discovery bug where files directly inside a hidden agent
directory were never matched. - PyPI packaging: complete project metadata, a release workflow
(.github/workflows/release.yml) that builds, runstwine check, and
publishes with PyPI trusted publishing (OIDC), and a version-consistency
test betweenpyproject.tomlandcairnlock.__version__. docs/rules-audit.md: rule-by-rule audit of scope, overlaps, and
agent-specific versus generic classification, pending review.- Redesigned ASCII banner: stacked CAIRN/LOCK block wordmark.
Changed
- Install docs lead with
pipx install cairnlockanduvx cairnlock scan;
the git+https install stays as a fallback. - Action description shortened below the 125-character marketplace limit.
v0.3.0
Added
cairnlock verify --base <git-ref>: readscairnlock.lockas it exists at
the given ref withgit showand compares the working tree against it. A
pull request that edits a tracked file and rehashes the lockfile in the
same change now fails with "lockfile modified in this change".--allow-lock-changeflag to permit lockfile-only changes.- Exit code 2 for usage and environment errors in verify: refs starting with
-are rejected before git runs, missing base lockfiles suggest running
cairnlock initon the base branch, and shallow clones get a
fetch-depth: 0hint for GitHub Actions. - All git calls use an argument list, never a shell.
base-refandallow-lock-changeinputs inaction.yml, with a verify
step that skips cleanly when no lockfile exists yet.- Marketplace metadata in
action.yml(name, description, branding). - Documentation site in
docs/: landing page, guide (lockfile workflow,
base verification, CODEOWNERS, CI), and a full rule reference. Plain HTML,
no build step. docs/rules.mdas the SARIF helpUri target for every rule id.SECURITY.mdwith reporting instructions and scope.- Dependabot config for pip and GitHub Actions.
- README section recommending CODEOWNERS protection for
cairnlock.lock.
Changed
- verify without a lockfile now exits 2 (usage/environment error) instead of 1.
- CLI status markers are plain text (
OK:,error:,warning:) instead of
emoji, per the project style rules. - SARIF driver version now comes from the package version instead of a
hard-coded string. - Ruff ignores E501; long regex pattern tables and embedded report templates
stay readable without manual line splitting.
Fixed
- CI lint failures:
ruff checkpassed locally on every configuration
tested before this release.
v0.2.0
Highlights
cairnlock 0.2.0 triples the rule set and adds rich reporting.
Added
- 12 new detection rules (18 total): SHC001 shell execution, NET001 network exfiltration, FSY001 filesystem access, ENV001 env manipulation, PRI001 privilege escalation, OBF001 obfuscation, SUP001 supply chain, CFG001 config/template injection, TOO001 tool calling injection, CRY001 crypto weakness, MCP003 unpinned dangerous commands, MCP004 sensitive env vars in MCP configs
- HTML and Markdown report output alongside text, JSON, SARIF 2.1.0
- New CLI commands: rules, stats
- ASCII banner, colored output, progress bars, verbose mode
- Shannon entropy validation for embedded secret detection
Changed
- SARIF output now includes help URIs and partial fingerprints
- Expanded MCP config analysis (4 rule IDs)
Fixed
- Secret detection false positives on placeholder values
- Cross-rule false positives in good fixtures
Install
pipx install git+https://github.com/pennacle-security/cairnlock.git@v0.2.0
0,1.0
Highlights
cairnlock 0.1.0 is the first release.
Added
cairnlock scanwith seven static detection rules:- HUC001: invisible/bidirectional Unicode in instruction files
- PIN001: prompt-injection phrases in tool/skill descriptions
- REM001: pipe-to-shell, base64 blobs, remote downloads in skill files
- MCP001: auto-approve/permission-skipping flags in MCP configs
- MCP002: filesystem server mounted at filesystem root
- UNP001: unpinned npx/uvx packages
- SEC001: embedded credentials
- Lockfile commands:
init,verify,diff,approve - Output formats: text, JSON, SARIF 2.1.0
- Composite GitHub Action (
action.yml) for CI and Code Scanning upload - Example pre-commit hook in
hooks/ - CI workflow running ruff and pytest on Python 3.11 and 3.13
Install
pipx install git+https://github.com/pennacle-security/cairnlock.git@v0.1.0