Skip to content

Security Model

We dogfood Firmis on itself. Every commit is scanned. And every version of this document is written by people who know exactly where the coverage ends. Honesty about limits is a feature, not a disclaimer.

Firmis is a static analysis scanner. It reads code and configuration files to find threats embedded before deployment. It cannot observe live agent behavior, intercept network traffic, or detect threats that only manifest at runtime. Here is exactly what it covers and where coverage ends.

Running entirely offline was a deliberate choice. We made it because:

  1. Your code is sensitive. Agent codebases often contain secrets, internal architecture, and proprietary logic. We never wanted to be in a position where we received that data by default.
  2. Offline means always available. No network dependency means the scan works in air-gapped environments, on developer laptops without internet access, and in CI without egress rules.
  3. Local analysis is fast. Round-tripping file content to a cloud service adds latency. Static analysis on 209 bundled rules takes under 5 seconds for most projects.

Cloud features exist and are opt-in. Everything in this document describes default offline behavior.

Firmis performs static analysis across four detection surfaces:

Detection SurfaceHowExample
Known-bad static patternsRegex, YARA-style string matching, text searchAWS key format (AKIA[0-9A-Z]{16}), C2 beacon byte signatures
Structural code patternsRegex on AST-adjacent code structurereadFileSync() result piped to fetch() POST body
Supply chain anomaliesPackage name matching against curated threat listsevent-stream dependency, typosquatted package names
Secret leakageHigh-entropy token pattern matchingOpenAI key (sk-...), GitHub PAT (ghp_...), PEM headers

A Firmis finding means: this pattern was found in a file scanned from your project. It does not mean an attack has occurred. It means a pattern associated with an attack technique exists in your codebase and requires human review to determine intent and risk.


Understanding the gaps is as important as understanding the coverage.

Not DetectedReasonAlternative
Runtime behavioral attacksFirmis is static — it does not run the agent or observe live executionRuntime monitoring, network egress filtering
Live prompt injection via user inputUser-supplied prompts are not scanned at runtimeInput validation at the application layer
Zero-day obfuscation techniquesNovel encoding or packing methods not yet in rule patternsBehavioral analysis, sandboxing
Encrypted payload contentFirmis cannot decrypt ciphertext to inspect payload intentRuntime unpacking, sandboxed execution
Semantic logic bombsLogic that is benign individually but malicious when composedCode review, threat modeling
Social engineering of agent operatorsNot a code-level threatSecurity training, operational procedures
Real-time session hijackingRequires live traffic inspectionmTLS, session token rotation
Model weight manipulationOut of scope for agent code scanningModel provenance verification

Every Firmis finding includes a confidence score (0–100) and a tier. Understanding these values helps you prioritize findings.

confidence = Math.max(ratioConfidence, maxSinglePatternWeight)

ratioConfidence — reflects breadth of evidence across the rule’s patterns:

ratioConfidence = (matchedPatterns / totalPatterns) × averageMatchedWeight

maxSinglePatternWeight — the weight of the single highest-weighted pattern that matched.

Taking the maximum of the two ensures that a single very strong indicator (e.g., an exact API key format match at weight 100) always produces a high confidence score, even if other patterns in the rule did not fire.

TierConfidence RangeMeaning
confirmed80–100High-specificity pattern match. Very low false-positive rate. Treat as finding until disproven.
likely55–79Multiple patterns co-occurring or one strong indicator. Review recommended.
suspicious0–54Weak or partial match. May represent benign code. Evaluate in context.

Severity is set by the rule author based on the real-world impact if the threat is real. A critical finding means:

  • The threat could result in credential compromise, data exfiltration, or arbitrary code execution
  • The confidence threshold for this rule has been set high to reduce false positives
  • Immediate review is warranted in most codebases

Severity is independent of confidence. A critical/suspicious finding means: “if this is what the rule thinks it is, it’s very dangerous — but the evidence is partial.”


Firmis is tuned for low false positive rates across typical AI agent codebases. However, false positives occur in specific scenarios.

ScenarioCategoryWhyMitigation
Test fixtures with hardcoded tokenssecret-detectionReal key format in test dataAdd path to .firmisignore
Documentation describing attack patternsprompt-injection, tool-poisoningExplanatory text matches attack patterns.firmisignore for doc paths
Security tools and scannersmalware-signaturesTools that manipulate or analyze malicious patterns.firmisignore for tool paths
Tutorials and example codesecret-detectionExample API keys in README.firmisignore for example directories
Legitimate broad permissions for platform toolspermission-overgrantSome orchestration tools genuinely need wide scopesAdd rule:perm-003 to .firmisignore

Files with .md and .txt extensions receive a 0.15x confidence multiplier before threshold comparison. A pattern that scores 80 confidence in a TypeScript file scores 12 in a Markdown file — below most thresholds. This suppresses noise from documentation files that describe threats without embedding them.

Exception: The secret-detection category is exempt from this multiplier. A hardcoded credential in a README or .env.example is still a real risk because it may be committed to a public repository.

Terminal
# Suppress a specific rule across all files
echo "rule:sd-045" >> .firmisignore
# Suppress all findings in a directory
echo "path:test/fixtures/" >> .firmisignore
# Suppress a specific rule in a specific file
echo "file:test/fixtures/sample.ts:rule:sd-045" >> .firmisignore

See Ignoring Findings for the full .firmisignore syntax.


Threat TypeDetected?HowLimitation
Hidden Unicode in tool descriptionsYesRegex pattern matching (tp-001)Only detects known Unicode ranges
Instruction override in tool metadataYesRegex pattern matching (tp-002)Novel phrasing may not match
MCP config file modificationYesAPI call pattern matching (tp-004)Only detects write-to-config patterns
File content sent to external URLYesComposite pattern (readFile + fetch)Requires co-occurrence in same file
AWS / GCP / Azure credential file accessYesfile-access pattern matching (cred-*)Does not detect indirect access via symlinks
Hardcoded API keys and tokensYesHigh-entropy regex (sd-*)Custom or low-entropy secrets may be missed
Compromised npm packagesYesString matching against curated list (supply-*)List requires updates when new incidents occur
Typosquatted packagesYesString distance matching (supply-*)Very subtle typos may evade detection
Tunneling service requestsYesNetwork pattern matching (na-*)Only matches known tunneling domains
Pipe-to-shell executionYesRegex pattern matching (md-001)Heavily obfuscated variants may evade
Runtime prompt injection via user inputNoNot a static patternRequires runtime input validation
Encrypted C2 payloadsPartialDetects encrypted blob shape, not decrypted contentCannot determine intent without decryption
Semantic logic bombsNoMulti-file compositional analysis not implementedRequires code review or symbolic execution
Zero-day obfuscationNoPatterns must exist in rule setRule updates needed for novel techniques

What we don’t do is as important as what we do.

PropertyGuarantee
Code never uploadedAll analysis happens locally. No file contents, paths, or findings leave your machine.
No telemetry by defaultFirmis collects no usage telemetry unless explicitly configured.
Read-only scanningFirmis never modifies scanned files. Running a scan changes nothing in your repository.
No code executionNo code in scanned files is run. Pattern matching operates on raw file content.
Offline operationAll 209 rules are bundled locally. Scanning works fully offline.