Skip to main content

Palisade

Website: https://arpankernel.github.io/palisade/ · Docs: https://arpankernel.github.io/palisade/docs/

Applied agentic-safety infrastructure. Palisade instruments the boundary where AI systems take real-world actions - detecting, evaluating, and gating the untrusted-input → model → dangerous-capability paths that are the near-term, tractable shape of loss-of-control risk. It runs on Python and JavaScript/TypeScript codebases, in CI, before they ship.

untrusted input  →  LLM  →  exec / shell / raw SQL   (no sanitizer)   ⇒  finding

The offline static core detects these paths with no API key, no signup, and no network calls - measured precision 1.000 on a pinned benchmark corpus. An opt-in layer (audit, review) adds grounded exploitability judgment and a safety-case posture over an endpoint you configure. Everything is MIT and free to run.

This is the applied arm of a long-horizon program to reduce catastrophic risk from autonomous AI: the failure it hardens today - untrusted input driving a model into a high-impact action with no oversight - is the same shape that scales as agents gain capability and autonomy. Palisade works the tractable, verifiable end of that problem: agentic safety, evals, safety cases, oversight, and governance at the application layer. It is engineering infrastructure, not frontier alignment research.

uvx palisade-sec scan .

palisade-sec scanning the example app

Same output as text
HIGH  app.py:31  [PI-EXEC] Prompt injection reaching code execution
  ↳ source:  question = request.json["question"]        (app.py:31)
  ↳ llm:     resp = client.chat.completions.create(     (app.py:32)
  ↳ sink:    exec(code)                                 (app.py:40)
  No sanitizer on path.  Confidence: HIGH
  Attack: crafted input makes the model emit Python that executes on your server.
  Fix:    never exec model output; sandbox + strict allowlist (denylists are bypassable).
  Refs:   CVE-2024-12366 (PandasAI); CVE-2025-3248 (Langflow, CISA KEV)

Documentation

Full docs are published at https://arpankernel.github.io/palisade/docs/ (source in docs/):

Getting started Install, first scan, reading a finding, CI gating - 5 minutes
End-to-end tutorial Full workflow on a sample app (examples/support-bot/): scan → fix → verify → baseline → CI
Architecture Frontends → taint IR → engine → rules; the precision philosophy; the safety contract
CLI reference Every command, flag, exit code, config key; the stable JSON schema
Rules reference All five builtin rules; pattern semantics; custom rules
For AI agents Machine contract: commands, JSON parsing, remediation policy (also llms.txt, AGENTS.md)
Roadmap Phases 0–6: Measure → Distribute → Cover → Scale → Certify → Expand → Remediate
Proof scans Evidence vs. real CVE repos - including the Vanna CVE-2024-5565 catch

Why

This exact pattern is behind real, exploited CVEs: Langflow (CVE-2025-3248, on CISA KEV, exploited in the wild), PandasAI (CVE-2024-12366, CVSS 9.8), Vanna.ai (CVE-2024-5565), LangChain PAL/LLMMath chains (CVE-2023-36258, CVE-2023-29374). Almost nobody defends it at the code level: existing tools are runtime proxies (paid, in the traffic path) or guardrail libraries you have to know to wire in. Palisade is the missing piece - free, static, LLM-dataflow-aware, and CI-native, like ruff or semgrep but for the OWASP LLM Top-10 #1 risk.

These CVEs are the small, exploited-today version of a larger problem: as systems become more agentic, the input → model → high-impact-action path stops being a web-app bug and becomes the loss-of-control surface. Hardening it now - with measured tooling, evals, and a defensible safety posture - is the applied, tractable end of reducing catastrophic risk from autonomous AI.

What it detects

Rule Path Real-world precedent
PI-EXEC input → LLM → exec / eval / new Function / vm.runIn* PandasAI, Langflow, LangChain PAL
PI-SHELL input → LLM → os.system / subprocess(shell=True) / child_process.exec Open Interpreter (by design)
PI-SQL input → LLM → raw non-parameterized SQL (cursor.execute, pool.query) Vanna.ai
PI-FRAMEWORK-EXEC input → framework LLM wrapper (submit_prompt, generate_code, ...) → execution step Vanna.ai, PandasAI
PI-HTTP input → LLM → model-chosen URL fetched (SSRF/exfil; advisory) OWASP LLM Top-10

Measured, not asserted. Against a pinned benchmark corpus of 26 third-party repos (17,343 files): precision 1.000, recall 0.667, F1 0.800

  • zero false positives, with the one miss (PandasAI's dynamically dispatched pipeline) labelled as a miss rather than deleted. The gate runs in CI, so precision can only ratchet upward. See docs/proof-scans.md.

Sources cover Flask (request.*), FastAPI (@app.post route params and pydantic bodies), Express (req.body/req.query), CLIs (input(), sys.argv, process.argv) - and, in library mode, public function parameters. Scanning the real vanna v0.5.5 with --assume-params-untrusted flags exactly the CVE-2024-5565 sink (base.py:1998) and nothing else.

Palisade runs taint analysis, not grep: it only reports a complete source → LLM → sink data-flow path with no sanitizer in between.

  • Constant developer prompt → LLM → exec? Silent - no untrusted source.
  • subprocess.run([...]) with an arg list? Silent - safe sink shape.
  • Parameterized cursor.execute(q, params)? Silent.
  • Allowlist / pydantic validation on the path? Silent - sanitized.
  • Denylist or human-confirmation gate? Flagged MED "risky" - real CVEs were exploited despite exactly those defenses. That is deliberate.
  • A "sanitizer" in name only - a project function matching sanitize/ validate whose body never actually validates? Flagged MED "unverified sanitizer" - Vanna's cosmetic _sanitize_plotly_code shipped CVE-2024-5565 straight through such a function.
  • Several rules matching one source → sink path? One finding - the most specific rule wins; no duplicate noise.

Two layers: offline core, optional judgment

Palisade is one open-source tool with two layers. The distinction is not free-versus-paid (it is all MIT and free); it is keyless-and-offline versus bring-your-own-endpoint.

Layer Commands Network Key
Offline core scan, map, baseline, fix none none
Judgment layer audit, review your endpoint your key (.env)
  • map inventories the AI surface of a codebase (LLM calls, prompts, tools, agents, retrieval, dangerous flags). Offline and keyless.
  • audit judges grounded findings: whether an agent tool has excessive agency, and whether a source → LLM → sink path is realistically exploitable. Every question is anchored to a fact the static analyzer verified.
  • review composes scan + map + the semantic checks into one prioritized report with a posture score (a number and a band over detected findings, not a safety score).

The judgment layer speaks any OpenAI-compatible endpoint, configured in .env (see .env.example); TypeSafe is the default and returns calibrated answers. A generic endpoint is supported as best-effort and never blocks CI on judgment alone. The exploitability and posture signals are uncalibrated until scored on the corpus; the deterministic scanner's precision (below) is unaffected by the judgment layer.

Install & run

# one-shot, no install
uvx palisade-sec scan path/to/project

# or
pipx run palisade-sec scan .

# or as a dev dependency
uv add --dev palisade-sec

# with the JavaScript/TypeScript frontend (tree-sitter)
uvx --from "palisade-sec[js]" palisade-sec scan .

Python is scanned out of the box; .js/.ts/.tsx files are scanned when the [js] extra is installed (otherwise they're skipped with a note).

Useful flags:

palisade-sec scan . --all          # also show MED/LOW findings
palisade-sec scan . --json         # stable machine-readable output
palisade-sec scan . --report       # write palisade-report.md
palisade-sec scan . --rules ./my-rules   # add your own YAML rules
palisade-sec scan . --assume-params-untrusted   # library mode, see below
palisade-sec fix .                 # remediation plan: guardrail + test per finding

palisade-sec fix

fix turns findings into a remediation plan (palisade-fixes.md): for each finding, a rule-tailored guardrail (AST allowlist for exec, arg-list + executable allowlist for shell, SELECT-only parser check for SQL, host allowlist + private-IP block for SSRF) plus a pytest asserting the guardrail blocks the canonical attack. Deterministic and offline - it never modifies your code and never calls an LLM.

Scanning libraries

Apps read untrusted input from request.* / input() / sys.argv. A library has no visible caller - its public parameters ARE the untrusted world (Vanna's ask(question), CVE-2024-5565). Library mode treats the parameters of public (non-underscore) functions as untrusted sources:

palisade-sec scan path/to/library --assume-params-untrusted

If the library routes LLM calls through its own wrapper method, add the wrapper to a custom rule's llm_signatures (e.g. "*.submit_prompt") - see the rules guide.

CI

Gate pull requests on new findings only - adopt Palisade on an imperfect codebase without a wall of pre-existing failures:

palisade-sec baseline .                 # once; commit .palisade/baseline.json
palisade-sec scan . --ci --baseline .palisade/baseline.json

--ci exits non-zero only if a new HIGH finding appears. Fingerprints are line-number independent, so refactors don't churn the baseline.

GitHub Actions:

- uses: astral-sh/setup-uv@v5
- run: uvx palisade-sec scan . --ci --baseline .palisade/baseline.json

Configuration

pyproject.toml:

[tool.palisade]
paths_ignore = ["migrations/*", "sandbox/*"]
include_tests = false   # tests/** and conftest.py are skipped by default
max_hops = 3            # inter-procedural depth bound
assume_params_untrusted = false   # library mode (see "Scanning libraries")

Or the same keys in .palisade.toml.

Custom rules

Rules are plain YAML validated by a pydantic schema - sources, LLM call signatures, sinks, sanitizers, partial defenses. Adding coverage for a new framework is a small PR with no engine changes. See src/palisade_sec/rules/README.md for the 5-minute guide.

Architecture

source ──▶ language frontends ──────────────────▶ normalized taint IR
           Python (stdlib ast)                          │
           JS/TS (tree-sitter, optional extra)          │
                              language-agnostic engine ─┤ taint propagation,
                              sanitizer resolution, confidence scoring
                                                        │
             YAML rules ──▶ findings ──▶ baseline diff ──▶ terminal / json / md

The frontend/IR split is the scalability story - proven, not promised: the JS/TS frontend landed with zero engine changes, and the same YAML rules match both languages (chat.completions.create, eval, child_process.exec are just dotted paths). Go and more come the same way.

Safety of the tool itself

  • Palisade never executes, imports, or evaluates scanned code - it only parses source text with ast.parse.
  • scan makes no network calls and needs no API key or account.
  • No telemetry. Nothing leaves your machine.

An honest note on scope

Palisade is one layer of defense against one class of vulnerability. A clean scan means no detected injection-to-sink path - it does not mean your application is secure. Keep your runtime guardrails, permissions boundaries, and sandboxes; Palisade complements them, before merge.

License

MIT

Release files for palisade-sec 0.5.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for palisade-sec 0.5.0
File Size Uploaded
palisade_sec-0.5.0.tar.gz 276.0 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for palisade-sec 0.5.0
File Interpreter ABI Platform
palisade_sec-0.5.0-py3-none-any.whl Python 3 none any Details

Total release size: 396.4 kB

Release files / palisade_sec-0.5.0.tar.gz

Download URL palisade_sec-0.5.0.tar.gz
Size 276.0 kB
Tags Source
SHA-256 checksum
How to use checksums
510c1c434878b2dea6ed7469193a320a4af66ce246bb056573175d7190c4045b
BLAKE2b-256 checksum
How to use checksums
ba2ac1552d9c6f54bef228ed83dc0a91a08320f39951e7d9d6ae916d6ce38578
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 Sep 20, 2026.

Transparency log

Release files / palisade_sec-0.5.0-py3-none-any.whl

Download URL palisade_sec-0.5.0-py3-none-any.whl
Size 120.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
be850e65bc861d142ef79ff430d57ff81e3d8cc23584d78e787cc061e5edac73
BLAKE2b-256 checksum
How to use checksums
95188cba5bf0dd04822ae237efe0d7b910dffd613f5b874727515f0cf8d73f26
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 Sep 20, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.5.0 This release

2 release files

0.4.0

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.2.0

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page