Documentation

Pinata is an AI-powered security scanner for AI-generated code. 47 detection categories. Six layers of defense. One command.

Installation

Run Pinata instantly with npx — no global install required:

        
terminal
$ npx --yes pinata-security-cli@latest analyze .

Or install globally for repeated use:

        
$ npm install -g pinata-security-cli

Requirements

Quick Start

Scan any directory with AI verification enabled:

        
$ pinata analyze ./src --verify Analyzing: /app/my-saas Project: Web server (high confidence) Files: 136 | Languages: TypeScript Scanning... ████████████████████ 100% AI Verification: 351 patterns → 3 confirmed vulnerabilities ┌─────────────────────────────────────────────────┐ │ CRITICAL SQL Injection api/users.ts:47 │ │ HIGH XSS views/comments.tsx:23 │ │ HIGH Command Inject utils/exec.ts:12 │ └─────────────────────────────────────────────────┘ Pinata Score: 72/100 (C) Run 'pinata generate --gaps --write' to create security tests
348 false positives eliminated

The AI verification layer (--verify) confirmed only 3 of 351 pattern matches were actually exploitable. Without it, you'd be chasing 348 ghosts.

API Key Setup

All Pinata plans require an API key. After subscribing, configure it:

        
$ pinata config set api-key your-api-key-here # Or use an environment variable $ export PINATA_API_KEY=your-api-key-here

Your API key enables:

Need a key?

Pick a plan at pinata.sh/pricing or email christian@pinata.sh to get started.

Configuration

Configure Pinata via CLI flags or a .pinatarc file in your project root:

        
.pinatarc
// .pinatarc (JSON) { "apiKey": "pk_...", "excludeDirs": ["node_modules", "dist", "vendor"], "minConfidence": "high", "output": "terminal", "verify": true, "failOn": "critical" }

CLI flags always override .pinatarc values.

pinata analyze

Scan a directory for security vulnerabilities:

        
$ pinata analyze [path] [options]
Option Description Default
--verify Enable AI semantic verification false
-c, --confidence Minimum confidence: high, medium, low high
-o, --output Output format: terminal, json, sarif, junit, markdown terminal
-d, --domain Filter by domain (security, data, auth, etc.) all
-v, --verbose Show detailed output with code context false
--exclude Directories to exclude (comma-separated) node_modules,dist
--fail-on Exit with code 1 if severity found: critical, high, medium

pinata generate

Generate security tests for confirmed vulnerabilities:

        
$ pinata generate --gaps --write Analyzing test coverage gaps... Found 3 untested vulnerability paths Generated: tests/security/sql-injection.test.ts Generated: tests/security/xss-comments.test.ts Generated: tests/security/cmd-inject.test.ts Running mutation verification... sql-injection.test.ts — kill rate 100% xss-comments.test.ts — kill rate 100% cmd-inject.test.ts — kill rate 100% 3 tests written. All mutations killed.
Option Description
--gaps Generate tests only for uncovered vulnerability paths
--write Write generated tests to disk (without this, tests are printed to stdout)
--framework Test framework: vitest, jest, mocha, pytest
--mutate Run mutation testing on generated tests to verify kill rate

pinata explain

Get AI-powered explanations for specific findings with remediation advice:

        
$ pinata explain sql-injection src/db/queries.ts:45 SQL Injection at src/db/queries.ts:45 The query concatenates user input directly into SQL: const query = `SELECT * FROM users WHERE id = ${userId}`; Risk: Attackers can inject malicious SQL to read, modify, or delete data. Could lead to full database compromise. Fix: Use parameterized queries: const query = 'SELECT * FROM users WHERE id = $1'; db.query(query, [userId]);

pinata dashboard

Launch the interactive TUI dashboard for a visual overview of findings:

        
$ pinata dashboard

Navigate with arrow keys, press Enter to drill into findings, q to quit.

pinata config

Manage persistent configuration:

        
$ pinata config set api-key pk_xxx $ pinata config get api-key $ pinata config list $ pinata config unset api-key

AI Verification

Pattern-based scanners flag everything that looks dangerous. Pinata's AI verification layer reads the code in context and determines whether a flagged pattern is actually exploitable.

This is what separates Pinata from tools like Semgrep or CodeQL — it understands that a SQL query using an ORM's parameterized builder isn't an injection risk, even if the syntax pattern matches.

How it works

  1. Pattern scan flags potential issues (fast, local, zero API calls)
  2. AI verification reads surrounding code context and confirms exploitability
  3. Only confirmed findings appear in your results

Enable with the --verify flag or set "verify": true in your .pinatarc.

Test Generation

Pinata generates runnable security tests for every confirmed vulnerability. Tests target the specific code path that's exploitable — not generic boilerplate.

Run pinata generate --gaps --write to:

Mutation Testing

Tests that always pass are worse than no tests — they give false confidence. Pinata's mutation testing mutates your security-critical code and verifies that your tests catch every mutation.

What it checks

Target: ≥95% kill rate for security-critical paths.

Dynamic Execution

For high-severity findings, Pinata can spin up a Docker sandbox and attempt to exploit the vulnerability in a live runtime. This produces real proof-of-concept output — not just static inference.

Requires Docker

Dynamic execution needs Docker installed and running. The sandbox is fully isolated — zero risk to your host environment.

CI/CD Integration

GitHub Actions

        
.github/workflows/security.yml
name: Security Scan on: [push, pull_request] jobs: pinata: runs-on: ubuntu-latest env: PINATA_API_KEY: ${{ secrets.PINATA_API_KEY }} steps: - uses: actions/checkout@v4 - name: Run Pinata Security Scan run: | npx --yes pinata-security-cli@latest \ analyze . \ --verify \ --format sarif \ --output results.sarif \ --fail-on critical - uses: github/codeql-action/upload-sarif@v3 if: always() with: sarif_file: results.sarif

GitLab CI

        
.gitlab-ci.yml
security-scan: image: node:20 variables: PINATA_API_KEY: $PINATA_API_KEY script: - npx --yes pinata-security-cli@latest analyze . --verify --output json > pinata.json artifacts: reports: sast: pinata.json
Block PRs with vulnerabilities

Use --fail-on critical to exit with code 1 if critical findings are detected. This fails the CI check and blocks the merge.

Output Formats

Format Flag Use Case
terminal --output terminal Human-readable output with colors (default)
json --output json Machine-readable JSON for scripting and automation
sarif --output sarif SARIF 2.1.0 — native GitHub Security tab integration
junit --output junit JUnit XML for CI systems (Jenkins, CircleCI, etc.)
markdown --output markdown Markdown report — paste into PR comments

Ignore Files

Create a .pinataignore file to exclude paths from scanning:

        
.pinataignore
# Test files (scan production code only) tests/ *.test.ts *.spec.js # Build output dist/ build/ .next/ # Dependencies node_modules/ vendor/ # Generated code *.generated.ts

Patterns follow .gitignore syntax.

Detection Categories

Pinata scans across 47 vulnerability categories organized into security domains:

Domain Categories Examples
Injection 8 SQL injection, XSS, command injection, LDAP injection, template injection
Authentication 6 Hardcoded credentials, weak hashing, missing rate limiting, session fixation
Data Exposure 7 Sensitive data in logs, missing encryption, PII leakage, debug endpoints
Access Control 5 Missing auth checks, IDOR, privilege escalation, CORS misconfiguration
Cryptography 4 Weak algorithms, predictable random, missing integrity checks
Infrastructure 6 SSRF, path traversal, open redirects, missing timeouts, DNS rebinding
AI-Specific 5 Prompt injection, unsafe eval, unvalidated AI output, training data leakage
Supply Chain 6 Dependency confusion, typosquatting, outdated packages, lockfile tampering

See the full list with descriptions: Detection Categories →

Scoring

Pinata calculates a security score from 0–100 based on:

Grade Score Meaning
A90–100Excellent — minimal or no findings
B80–89Good — some low-severity findings
C70–79Moderate — action recommended
D60–69Below average — significant gaps
F0–59Poor — immediate action needed

Troubleshooting

API key not working

Verify your key is set correctly:

        
$ pinata config get api-key # Should show pk_**** (masked) # Or check environment $ echo $PINATA_API_KEY

Scan takes too long

False positives

If you're seeing false positives, make sure --verify is enabled. Pattern-only scanning (without AI verification) will always have more noise. You can also suppress specific findings with inline comments:

        
// pinata-ignore: sql-injection — using parameterized ORM builder const users = await db.users.findMany({ where: { id: userId } });

Need help?

Email christian@pinata.sh — we respond within 24 hours.