Open source · MIT · the scanner runs locally, no API key

Meet Palisade. Your AI's safety engineer.

AI can be tricked into leaking data, running commands, or hitting your database. Palisade is the engineer that finds those weaknesses, tests them, and blocks them before you ship - one command, right in your pipeline.

a crafted message ──▶ your AI ──▶ a dangerous action (no guardrail) ⇒ caught
Star on GitHub ↗
JavaScript / TypeScript? add the extra: uvx --from "palisade-sec[js]" palisade-sec scan .
precision 1.000 · 0 false positives across 17,343 files of real code · never executes your code
palisade-sec · scan
uvx palisade-sec scan .HIGH app.py:34 [PI-SQL] Prompt injection reaching raw SQL source: question = request.json["question"] (app.py:24) llm: resp = client.chat.completions.create( (app.py:25) sink: cur.execute(sql) (app.py:34) No sanitizer on path. Confidence: HIGH · CVE-2024-5565 (Vanna.ai)HIGH app.py:64 [PI-EXEC] Prompt injection reaching code execution source: spec = request.json["spec"] (app.py:56) llm: resp = client.chat.completions.create( (app.py:57) sink: exec(code) (app.py:64) Attack: crafted input makes the model emit Python that runs on your server. Fix: never exec model output; sandbox + strict allowlist.MED app.py:97 [PI-EXEC] (risky: partial defense only - denylists are bypassable)Found 2 high, 1 med finding(s) in 6 file(s). exit 1 (--ci)
0
files checked · zero false alarms
0 CVE
real Vanna CVE found, exact line
~0
to scan a 1,576-file codebase
0 rules
python · js/ts · one engine
The risk

A sentence can turn your AI against you.

Feed a model untrusted text and its answer can reach the real world - your shell, your database, an outbound request - running with your privileges. It is the #1 risk on the industry's LLM list, it has already been exploited in the wild, and no prompt fully prevents it. The one place you can reliably catch it is your code, before it ships.

LLM01
THE #1 RISK

Ranked first, still unsolved

OWASP puts prompt injection at the top of the LLM Top-10, two editions running. The model vendors agree it can't be fully prevented at the model layer.

IN THE WILD
NOT THEORETICAL

Real CVEs, this exact shape

Langflow's injection → exec path (CVE-2025-3248) is on the CISA KEV list, exploited in the wild. PandasAI (CVE-2024-12366, CVSS 9.8) and Vanna (CVE-2024-5565) shipped the same pattern.

THE FIX
CATCH IT EARLY

Find it in code, before it ships

You can't fix the model, but you can find every place a manipulated answer could reach something dangerous - and block it in your pipeline before it ever reaches production.

How it works

It reads your code the way an attacker would.

Palisade follows the path from untrusted input, through the model, to anything dangerous - and only flags a real, complete path with no guardrail in between. Calling an AI is never a finding on its own. That one rule is why it almost never cries wolf.

01FRONTEND

Parse

Python via stdlib ast, JS/TS via tree-sitter. Source text only - scanned code is never executed.

02IR

Lower

Both languages compile to one normalized taint IR. Import aliases resolve, so sp.run is subprocess.run.

03ENGINE

Propagate

Taint flows through f-strings, collections, awaits, class fields, and bounded cross-file calls - 3 hops deep.

04JUDGE

Verify defenses

Real sanitizers suppress. Denylists, confirmation gates, and sanitizers-in-name-only downgrade - never silence.

05EMIT

Report

Full trace per finding: source, LLM, sink, attack, fix, CVE refs. Terminal, stable JSON, or markdown threat model.

What it catches

Five taint rules, plus multi-agent handoffs. Each mapped to a real CVE class.

Rules are plain YAML - sources, LLM signatures, sinks, sanitizers. Adding coverage for your framework is a data change, never an engine change. The CVEs below name the vulnerability class each rule covers; the proof section shows what is verified end-to-end, including the one documented miss.

HIGH
PI-EXEC

Injection → code execution

Model output executed as code. The most common real-world LLM vulnerability class.

exec · eval · compile · PythonREPL
new Function · vm.runIn*
CVE-2024-12366 · CVE-2023-36258
HIGH
PI-SHELL

Injection → OS command

Model output handed to a shell verbatim. Arg-list subprocess.run([...]) stays silent.

os.system · subprocess(shell=True)
child_process.exec / execSync
Open Interpreter class (by design)
HIGH
PI-SQL

Injection → raw SQL

Text-to-SQL executed non-parameterized. execute(q, params) stays silent.

cursor.execute · executemany · Model.raw
pool.query · db.query
CVE-2024-5565 · CVE-2024-5826
HIGH
PI-FRAMEWORK-EXEC

Framework wrapper → execution step

Agent frameworks hide the LLM behind wrappers. Palisade knows the shapes: submit_prompt, call_llm, generate_code

*.execute_code · *.run_code · *.execute_plan
Vanna · PandasAI pipeline class
MED · ADVISORY
PI-HTTP

Injection → SSRF / exfiltration

Model-chosen URLs fetched directly - cloud metadata, internal APIs, attacker hosts. Advisory: never gates CI.

requests.* · httpx.* · urlopen (URL arg only)
OWASP LLM Top-10 · SSRF
HIGH
PI-AGENT-HANDOFF

Injection → agent handoff → dangerous tool

Multi-agent path: untrusted input runs an agent that hands off (≥1 hop) to an agent holding a dangerous-capability tool. Deterministic and offline.

OpenAI Agents SDK · LangGraph · CrewAI
agentic prompt-injection class
YOURS
PI-CUSTOM

Your framework, one YAML file

Your codebase routes LLM calls through self.inference()? Add one line to llm_signatures, pass --rules ./dir. Same id overrides a builtin.

sources · llm_signatures · sinks · sanitizers
Why you can trust it

It doesn't cry wolf.

A security tool that raises false alarms gets ignored, then uninstalled. So Palisade holds itself to precision as the product: every "won't flag" below is locked by a permanent test, and every false alarm anyone reports becomes one too.

Stays silent - safe shapes
  • PASSConstant developer prompt → LLM → exec - no untrusted source, no finding
  • PASSsubprocess.run([...]) with an arg list and no shell
  • PASSParameterized SQL - execute(q, params), pool.query(text, values)
  • PASSpydantic / marshmallow validation on the path
  • PASSVerified project sanitizers - allowlists and guards that actually raise
  • PASSLLM output that is only logged, printed, or returned
Still flagged - real CVEs shipped through these
  • MEDDenylists. LangChain PAL's COMMAND_EXECUTION_FUNCTIONS denylist was bypassed → CVE-2023-36258
  • MEDConfirmation gates. "Are you sure?" is not a security boundary
  • MEDSanitizers in name only. Vanna's _sanitize_plotly_code stripped fig.show() - and shipped CVE-2024-5565. Palisade verifies the body, not the name
  • HIGHMulti-hop paths. Source in one file, LLM in a second, sink in a third - traced across the call graph
  • HIGHHidden flows. json.loads(output)["cmd"], f-strings, parts.append(...), self.x class fields
"A false positive is worse than a miss - noise trains developers to ignore all security warnings."Design philosophy #1, enforced by the test suite
The receipts

Point it at the repo behind a real CVE.

We scanned the actual vulnerable releases of the projects that motivated Palisade - and published the misses alongside the hits.

vanna v0.5.5 · the release behind CVE-2024-5565
palisade-sec scan vanna-0.5.5 --assume-params-untrustedMED src/vanna/base/base.py:1998 [PI-FRAMEWORK-EXEC] source: param:question - ask() (base.py:1594) llm: self.submit_prompt(message_log) sink: exec(plotly_code, globals(), ldict) Unverified sanitizer: _sanitize_plotly_code - matches a sanitizer name, but its body shows no allowlist/validation shape. the CVE sink. Zero other findings across the 45-file repo.
HIT

The exact CVE line, nothing else

Builtin rules + library mode land on base.py:1998 - the sink NVD lists for CVE-2024-5565 - and correctly call out the cosmetic sanitizer that failed in the wild.

HELD

Zero false positives at scale

A pinned corpus of 26 third-party repos, 17,343 files, scored in CI: precision 1.000, recall 0.667. Not one wrong flag, and the single miss is labelled as a miss rather than deleted.

HONEST

Misses are documented, not hidden

PandasAI's dynamic pipeline dispatch beats bounded static taint. We say so, and it defines the roadmap. Read the full proof-scan report →

Adopt in an afternoon

Scan. Gate. Fix.

Baseline your existing debt, fail CI only on new findings, and generate a guardrail + regression test for every finding you burn down.

Gate CI on new findings

github actions
# .github/workflows/security.yml
- uses: astral-sh/setup-uv@v5
- run: |
    uvx palisade-sec scan . --ci \
      --baseline .palisade/baseline.json
Line-shift-resilient fingerprints - refactors never churn the baseline.

Fix with proof

palisade-sec fix
$ palisade-sec fix .
→ palisade-fixes.md

# per finding: a tailored guardrail
# + a pytest proving it blocks the
# canonical attack. Offline. Never
# edits your code.
AST allowlists, argv allowlists, SELECT-only SQL validation, SSRF guards.

Built for AI agents

llms.txt · agents.md
$ palisade-sec scan . --json
{ "schema_version": 1, ... }

# stable schema · exit-code contract
# remediation policy · fingerprint
# diffing - the full agent contract
The whole job

One engineer. The whole safety job.

Finding the risk is where Palisade starts. A real safety engineer also stress-tests the system, argues it is safe with evidence, gates the risk in your pipeline, and keeps a human in charge as AI writes more of the code. Palisade is growing into all of it - one honest tool across every facet of AI safety engineering. Each piece is marked for what it does today versus what is still being built.

CORE SHIPPED
01 · AGENTIC & MULTI-AGENT SAFETY

The action boundary

Where a model reaches a real capability - exec, a shell, SQL, an outbound call. This is the loss-of-control surface as autonomy grows.

today · scan input→model→sink · PI-AGENT-HANDOFF
today · map agents + handoffs (openai · langgraph · crewai)
today · audit excessive agency
next — deeper cross-agent taint · autogen graphs · conditional-edge coverage
PARTIAL
02 · EVALS & RED-TEAMING

Exercise it adversarially

Attack the system with inputs built from its own map, and measure what lands - on a pinned, reproducible harness rather than a vibe.

today · red-team synthesis from the live map
today · gated red-team execution (HttpTarget + scorer)
today · pinned 26-repo precision gate in CI
next — calibrated per-check P/R on a full benchmark corpus
PARTIAL
03 · SAFETY CASES & ASSURANCE

Argue the residual risk

A structured, evidence-backed argument a decision-maker can accept - not a bare score. Every claim traces to a fact the engine can prove.

today · review + posture over verified facts
today · measured-not-asserted discipline
next — claims → evidence → residual-risk export for auditors
BUILDING
04 · TECHNICAL AI GOVERNANCE

Make it enforceable

Turn safety practice into an organizational requirement a pipeline enforces, with an audit trail teams and regulators can read.

today · CI gates · exit-code contract
today · SARIF + GitHub code-scanning Action
today · stable JSON schema · disclosure policy
next — CWE / OWASP-LLM tags · signing / SBOM / provenance
ENFORCED
05 · CHECKABLE OVERSIGHT

Keep a human in control

Keep AI-assisted work verifiable as models begin to exceed human review. Advisory by default; a person holds the gate on anything that acts.

today · grounded to ground truth
today · approval gates · unverified-can't-act
today · never executes your code
next — gate AI-authored diffs · re-verifiable evidence output
SHIPPED
06 · MEASURED GROUND TRUTH

Why the ambition stays honest

Every judgment is anchored to a deterministic finding the engine can prove. The floor under the whole roadmap is a real, measured detector.

today · LLM-aware taint core
today · precision 1.000 across 17,343 files
today · zero false positives
honest — the judged layer has a preliminary seed-corpus calibration; full-benchmark calibration is pending, so it stays advisory. The core's precision stands alone
FAQ

The questions people ask first.

A linter is the foundation, and that is deliberate: every safety claim is anchored to a deterministic finding Palisade can prove. On that ground truth it does more of an AI safety engineer's job - mapping the action surface, red-teaming it, arguing residual risk, and gating AI-assisted changes. It works the applied, verifiable end of the problem: safety for agentic systems at the deployment layer. It is not frontier alignment research, and it does not claim to be.

The taint core - single-agent paths and multi-agent handoff detection - is shipped and gated in CI at precision 1.000, and SARIF output plus gated red-team execution ship alongside it. The judged layer (audit, review, posture) runs today with a preliminary seed-corpus calibration but no full-benchmark precision/recall yet, so it is advisory and can never gate CI or raise a critical posture on its own. Deeper cross-agent taint, governance tags and SBOM/signing, and the oversight-of-AI-code mode are on the public roadmap, marked building. We would rather show the frontier than blur it.

No. scan is pure static analysis: it parses source text and never executes, imports, or evals it - a live test in the suite proves scanned code cannot run. There are no network calls, no telemetry, no accounts, and no API key. The only writes are .palisade/ and files you explicitly request. The optional judgment layer (audit, review) is the only part that reaches an endpoint, one you configure in .env; it is all MIT and free, it currently has a preliminary seed-corpus calibration and stays advisory, and the core never calls out.

Bandit flags exec() anywhere; Semgrep matches patterns you write. Palisade runs LLM-aware taint analysis: it only fires on a complete untrusted-input → LLM → sink data-flow path, understands LLM SDK response shapes, and judges defenses - denylists and cosmetic sanitizers downgrade instead of silencing. It's the layer those tools don't model, and it composes fine with both.

Zero across a pinned benchmark corpus of 26 third-party repos and 17,343 files, measured in CI rather than claimed. The mechanism: findings require the full path, safe shapes (arg-list subprocess, parameterized SQL, verified sanitizers, constant prompts) are recognized, and every reported FP becomes a permanent must-stay-silent test. Misses are documented publicly in the proof-scan report.

Yes - install with the extra: pip install "palisade-sec[js]" or uvx --from "palisade-sec[js]" palisade-sec scan .. A tree-sitter frontend lowers JS/TS into the same taint IR with zero engine changes, so the same YAML rules match Express req.body, eval, new Function, child_process.exec, and pool.query.

Library mode: --assume-params-untrusted treats the parameters of public functions as untrusted sources - a library's callers are the untrusted world. That's exactly how Palisade finds the real CVE-2024-5565 sink in vanna v0.5.5 with builtin rules and nothing else.

No, and we won't pretend otherwise. Palisade is one layer against one class of vulnerability - code-level injection-to-sink paths. Keep your runtime guardrails, permission boundaries, and sandboxes. Palisade complements them, before merge.

Free forever · MIT

Put a safety engineer
on your AI.

One command, 30 seconds - no key, no signup, no code leaving your machine. Find where your AI could be turned against you, before it ships.