Open-source supply-chain & container security scanner for source code, npm dependencies, Docker images, GitHub repos, and CI/CD pipelines.
Palisade is a lightweight, plugin-based scanner that helps developers detect compromised dependencies, vulnerable Docker images, leaked secrets, misconfigured GitHub Actions, and newly disclosed CVEs — early, locally, and without sending your code to a third party.
Designed for: individual developers · small teams · OSS maintainers Not designed for: SaaS-only enterprise compliance workflows. If that's what you want, look at Snyk/Sonatype/Wiz.
| Capability | Built-in scanners |
|---|---|
| npm supply chain | Lockfile vuln scan (OSV/GHSA), typosquat detection, postinstall script analysis, obfuscated-code heuristics, malicious-package check |
| Secrets | AWS keys, GitHub PATs, GCP service-account JSON, Slack tokens, JWTs, private keys, generic high-entropy strings — with redaction |
| Docker | Dockerfile static analysis + image layer scan (CVEs on OS packages from dpkg/apk/rpm), running-as-root, unpinned base images, secrets in ENV |
| GitHub posture | Branch protection, CODEOWNERS, unpinned actions, excessive token permissions, missing signed commits |
| Intel feeds | OSV.dev · GitHub Security Advisories · NVD · CISA Known Exploited Vulnerabilities · OpenSSF Scorecard |
| Output | Rich terminal · JSON · SARIF 2.1.0 (GitHub Code Scanning) · Markdown reports |
| Delivery | CLI · GitHub Action · GitHub Issue / Slack / Discord / Webhook notifications |
Offline-capable after palisade update-intel. No telemetry. No phone-home.
pip install palisade-scanner
# (the CLI command is `palisade` — the PyPI name is `palisade-scanner`
# because `palisade` was already taken on PyPI by an unrelated project)
# Or, from source:
git clone https://github.com/pklooster/palisade
cd palisade && pip install -e ".[dev]"# Sync vulnerability intel (run once a day; cached locally in ~/.palisade/intel.db)
palisade update-intel
# Scan a repo
palisade scan repo ./my-project
# Scan a Docker image
palisade scan image my-org/my-app:latest
# Scan a remote GitHub repo (posture + lockfiles via API)
palisade scan github owner/repo
# Emit SARIF for GitHub Code Scanning
palisade scan repo . --format sarif --output palisade.sarif
# Fail CI on high+ severity findings
palisade scan repo . --fail-on high# .github/workflows/security.yml
name: Security scan
on: [push, pull_request]
jobs:
palisade:
runs-on: ubuntu-latest
permissions:
contents: read
security-events: write
steps:
- uses: actions/checkout@v4
- uses: pklooster/palisade/.github/actions/scan@v0.1.0
with:
path: .
fail-on: highSee examples/workflows/ for more.
palisade scan repo <path> Scan a local repo (npm + secrets + dockerfile)
palisade scan image <ref> Scan a Docker image (local or registry)
palisade scan github <owner/repo> Remote scan via the GitHub API
palisade watch github <owner/repo> Poll a repo and notify on new findings
palisade update-intel [--feed NAME] Refresh local vulnerability intel cache
palisade generate-sbom <target> CycloneDX 1.5 JSON SBOM
palisade audit-config <path> Posture audit (IaC, workflows, repo settings)
palisade list-scanners List loaded scanner plugins
palisade list-feeds | list-reporters | list-notifiers
palisade rules list | explain <id> Inspect built-in detection rules
Global flags: --format {text,json,sarif,markdown} · --output PATH · --config FILE · --offline · --severity-threshold {critical,high,medium,low,info} · --fail-on LEVEL · --no-color
Exit codes: 0 clean · 1 findings ≥ --fail-on · 2 internal error.
Project-level config lives at palisade.yaml in your repo root:
# Annotated example: see examples/palisade.yaml
scanners:
enabled: [npm, secrets, dockerfile, image, github]
npm:
fail_on_postinstall: true
typosquat_distance: 2
secrets:
extra_rules: ./custom-secret-rules.yaml
exclude_paths: ["docs/**", "tests/fixtures/**"]
intel:
feeds: [osv, ghsa, kev]
cache_dir: ~/.palisade
offline: false
reporters: { format: sarif, output: palisade.sarif }
notifiers:
github_issue:
enabled: true
repo: $GITHUB_REPOSITORY
severity_threshold: highA thin orchestrator core loads four plugin types via Python entry points:
┌──────────────────────────────────────────────────────────────┐
│ CLI / Action │
└───────────────┬─────────────────────────────────┬────────────┘
│ │
▼ ▼
┌──────────────┐ ┌────────────────┐
│ Orchestrator │◄────IntelCache──►│ IntelFeed(s) │ ← OSV, GHSA, NVD, KEV
└──────┬───────┘ (SQLite, local) └────────────────┘
│
┌──────┴────────────┐
▼ ▼
┌──────────────┐ ┌──────────────┐
│ Scanner(s) │ │ Reporter(s) │ → text · JSON · SARIF · MD
└──────┬───────┘ └──────────────┘
│
▼ findings
┌──────────────┐
│ Notifier(s) │ → GitHub Issue · Slack · Discord · Webhook
└──────────────┘
Scanners NEVER hit the network — all vulnerability intel goes through the local SQLite cache. This makes --offline trivial and tests deterministic. See docs/architecture.md.
# my_scanner.py
from palisade.scanners.base import Scanner
from palisade.models import Finding, Severity, FileTarget
class MyScanner:
name = "my-scanner"
target_kinds = {"repo"}
def scan(self, target, ctx):
for path in ctx.workspace.rglob("*.config"):
if b"DEBUG=true" in path.read_bytes():
yield Finding(
rule_id="my.debug-enabled",
scanner=self.name,
severity=Severity.MEDIUM,
title="Debug mode enabled in config",
target=FileTarget(path=str(path.relative_to(ctx.workspace))),
remediation="Set DEBUG=false in production configs.",
)Register via pyproject.toml:
[project.entry-points."palisade.scanners"]
my-scanner = "my_package.my_scanner:MyScanner"Full guide: docs/plugin-authors.md.
Palisade is designed to be safe to run on untrusted code. It:
- Parses lockfiles and Dockerfiles statically — never executes
postinstallscripts. - Reads Docker images by parsing
docker savetarballs locally; no container runtime needed. - Talks to intel APIs over HTTPS with strict TLS verification; pinned via
httpx. - Caches all intel locally — supports fully
--offlineoperation. - Has zero telemetry.
See docs/threat-model.md for the full STRIDE analysis.
- v0.1 (this release): CLI, npm/secrets/dockerfile/image/github scanners, OSV+GHSA+KEV feeds, SARIF, GitHub Action.
- v0.2: PyPI + Maven ecosystems; Sigstore/Rekor verification; CycloneDX 1.6; SLSA provenance.
- v0.3: IaC scanner (Terraform / Helm / k8s); deep GitHub Actions YAML scan; ML-assisted secret detection.
- v0.4:
watchdaemon; differential PR scans; webhook-driven re-scan. - v1.0: Stable plugin API; signed releases; community rule packs.
Full roadmap: docs/roadmap.md.
Palisade is not trying to replace Trivy, Grype, or Semgrep. It complements them by focusing on supply-chain + repo-posture signals with a small, hackable Python codebase that's easy for OSS maintainers to extend.
We welcome contributions! See CONTRIBUTING.md for setup, style, and PR guidelines.
For security issues, see SECURITY.md — please do not open public issues for vulnerabilities.
palisade — a defensive wooden wall used to protect a perimeter. The project was almost called tripwire, vigil, or auditron; all good names, none of them as evocative.
Apache 2.0 — see LICENSE.