One verb, run, everything else is a flag.
One verb, run. Point it at a target, add flags to shape the scan and
the output. Nothing under inspection is ever loaded, imported, or executed.
The target argument is the one thing every invocation needs.
AMARA infers which connector to use from its shape, force one explicitly with
--source when the shape is ambiguous.
targetrequired · positionalorg/model, hf://org/model, or a huggingface.co URL./tree/<ref>/<path>.llama2, llama2:7b.pkg, pkg@1.2.3, @scope/pkg.pkg, pkg==1.2.3.Ollama, npm, and PyPI names are ambiguous with a local path, so
they need an explicit --source. They're never auto-detected.
--sourcehuggingface · github · ollama · npm · pip · localForces a specific connector instead of auto-detecting from the target's shape.
auto (the default) picks huggingface for org/model
and huggingface.co URLs, github for github.com URLs, and local for
an existing path. Required for Ollama, npm, and PyPI targets, also the escape hatch when
auto-detection picks wrong.
--revisionPin to a specific branch, tag, or commit (Hugging Face, GitHub) or tag (Ollama). An unpinned
fetch is unreproducible and silently re-poisonable, the upstream ref can change between
your scan and someone else's pull. Omitting it on a dataset is exactly what
DATASET.PROVENANCE_UNPINNED flags.
Every flag on amara run, what it does, why or when to reach for it,
and a runnable example.
--format / -ftable (default) · json · sariftable, colorized terminal summary. json, full machine-readable
report. sarif, SARIF 2.1.0 for GitHub code scanning and similar dashboards.
--fail-oninfo · low · medium · high · criticalExit 1 if any finding meets or exceeds this severity. Without it, a successful
scan always exits 0 regardless of findings, set it explicitly to gate CI.
--max-sizebytesSkip, and flag as an error, any artifact larger than this many bytes, caps fetch time and disk use against unexpectedly huge files.
--allflagScan every file, not just risky model extensions (.bin, .pt,
.pkl, .ckpt, .safetensors, .gguf, …).
Use it for a full release audit, the default filter keeps routine scans fast.
--manifestpathPath to known-good SHA-256 digests (sha256sum, YAML, or JSON). Fetched files
are compared against it; mismatches and unlisted files are flagged, pins exactly which
bytes you trust, independent of what the hub claims.
--policypath to YAMLOverrides the default policy (block high/critical, quarantine medium) with your own allow / quarantine / block rules. Use it when your team's risk tolerance differs per severity, scanner, or finding ID.
Writing a policy. Data, not code: a name, a default action,
and a list of rules. The verdict is the strictest matching action
(block > quarantine > allow), falling back to
default if nothing matched.
Fields under when (AND'd within a rule, add
more rules for OR-style logic):
When it's useful:
count_at_least to catch a pattern rather than a single false positive.policy.yaml for release branches than for local dev.--dataset-scanopt-inRuns the dataset content scanners, PII, weaponized rows, label anomalies, backdoor
triggers, spectral/outlier poison detection. File-safety and provenance checks always run
regardless. Opt-in because it parses row data, not just bytes; turn it on for any dataset
you'll actually train on. Parquet/Arrow needs the amara[datasets] extra.
--llm-scanopt-inSource-level analysis of LLM call sites. Widens the fetch set to source, config, and markdown files. Nothing runs, Python is parsed to an AST only.
allow_dangerous_code / trust_remote_code.--mcp-scanopt-inReviews MCP server manifests and MCP-decorated tools. Use it whenever a repo ships an MCP server or client config, nothing is launched by the scan.
curl | sh launch commands.npx/uvx packages, or remote code fetch at launch.--agent-scanopt-inReviews dangerous agent capabilities and the documents an agent reads. Use it whenever a repo hands an LLM tools or reads documents into context. Nothing is executed.
--full-scanopt-inShorthand for --llm-scan --mcp-scan --agent-scan --dataset-scan together, every
opt-in analyzer at once. Use it for a release audit or a "scan everything" CI job.
--data-bompathWrites a Data-BOM, source, revision, and per-file format/size/SHA-256, as JSON. Diff it between runs to catch a dataset or model that drifted, or was never pinned.
--output / -opathWrites the report to this file instead of stdout, pairs naturally with
--format sarif or --format json for a downstream upload step.
--verbose / -vflagPrints progress to stderr, connector, each fetch, each scanner's finding count. Stdout
stays exactly the report, so piping to jq still works with it on.
--versionflagPrints the installed AMARA version and exits.
Each scanner registers as a plugin via amara.scanners entry points and
runs when its format applies. Model and file-safety/provenance dataset scanners run by
default; the four marked opt-in require
--dataset-scan, --llm-scan, --mcp-scan, or
--agent-scan (--full-scan enables all four at once).
| Scanner | Formats | Detects | Runs |
|---|---|---|---|
| pickle | .pkl/.pickle/.pt/.pth/.bin/.ckpt/.joblib, pickles inside PyTorch zips & tar.gz | Dangerous globals with the real payload argument, unknown/unresolved globals, trailing-data evasion, malformed streams | default |
| archive | .zip, PyTorch zips, .tar.gz/.tgz | Zip-Slip path traversal, symlinks/hardlinks, device/FIFO members, decompression bombs, suspicious names, corrupt archives | default |
| keras | .h5/.hdf5, Keras v3 .keras | Lambda/TFOpLambda layers embedding arbitrary Python run at load time | default |
| onnx | .onnx | external_data path traversal, non-standard custom operator domains | default |
| tf-savedmodel | saved_model.pb / .pb GraphDef | Dangerous graph ops: PyFunc, ReadFile, WriteFile, ImmutableConst | default |
| tflite | .tflite | Custom operators needing a native plugin; Flex delegate ops exposing the full TF op set | default |
| dataset-loader | .py loading/custom-code scripts | AST-only analysis of shell-out, dynamic eval/exec/import, network egress, unsafe deserialization, destructive filesystem writes | default |
| dataset-file | .parquet, .arrow/.feather, .tfrecord | Embedded pickle smuggled in a data column; embedded ELF/PE/Mach-O executables | default |
| dataset-provenance | all dataset files | A dataset fetched without a pinned revision, unreproducible, silently re-poisonable | default |
| dataset-content | .jsonl, .csv, .parquet, .arrow | PII, weaponized rows, verbatim duplication, label anomalies, backdoor triggers, spectral/distance outlier poison scoring | --dataset-scan |
| app-scan | .py | Model output / tool parameters reaching a dangerous sink, dangerous agent capabilities, hardcoded keys, prompt-injection surfaces | --llm-scan / --mcp-scan / --agent-scan |
| mcp | MCP manifests (.json/.yaml declaring mcpServers) | curl | sh launches, unpinned packages, remote code fetch, auto-approved tools, pasted secrets, insecure transport, directive text in descriptions | --mcp-scan |
| agent-prompt | .md, .txt, .rst, .yaml, prompt templates | Indirect prompt injection: instruction override, concealment, credential exfiltration, jailbreak personas, including invisible-Unicode payloads | --agent-scan |
| integrity | all | Records SHA-256; flags mismatches against a source digest or --manifest | default |
| format | all | Identifies on-disk format and base risk; flags unresolved Git LFS pointers | default |
Every finding carries a stable, greppable tag, SCANNER.RULE, so
policies and dashboards can key off it. Severity drives the verdict; here is what each tag
means.
PICKLE.DANGEROUS_GLOBALA pickle references a known RCE/exfil gadget (os.system, subprocess, eval, runpy._run_code…), with the actual payload argument shown.
DATASET.LOADER_OS_EXECA dataset loading script shells out via os.system / subprocess, arbitrary command execution under trust_remote_code.
DATASET.LOADER_DYNAMIC_EXECA loader script builds and runs code at runtime with eval / exec.
DATASET.EMBEDDED_PICKLEA malicious pickle hidden inside a Parquet/Arrow data cell that would execute on read_parquet.
TFLITE.FLEX_DELEGATE_OPA TFLite Flex op hands the node to the full TensorFlow op set, the same code-execution surface as a SavedModel graph.
TF.DANGEROUS_OPA TensorFlow graph uses a filesystem/code op such as PyFunc, ReadFile, or WriteFile (severity scales with the op).
AGENT.TOOL_COMMAND_INJECTIONA parameter of an LLM-callable tool reaches a shell, the LLM, not the developer, controls the argument.
LLM.CONVERSATION_EXFILTRATIONPrompts and completions are posted to a third-party host that is not an LLM provider, a conversation-logging backdoor.
PICKLE.SUSPICIOUS_STRINGA pickle carries an embedded weaponized payload string, a reverse shell, download-and-execute pipeline, or encoded PowerShell.
KERAS.LAMBDA_LAYERA Keras Lambda / TFOpLambda layer embeds arbitrary Python executed at model-load time.
ONNX.EXTERNAL_DATA_PATH_TRAVERSALAn ONNX tensor's external_data path escapes the model directory, arbitrary file read on load.
ARCHIVE.PATH_TRAVERSALZip-Slip: an archive member's path escapes the extraction directory to overwrite arbitrary files.
ARCHIVE.SYMLINKAn archive contains a symlink/hardlink member that can redirect a later write outside the target tree.
ARCHIVE.SUSPICIOUS_MEMBER_TYPEA device, FIFO, or other special-file member in an archive, never legitimate in a model package.
DATASET.EMBEDDED_EXECUTABLEA native ELF / PE / Mach-O binary embedded inside a dataset shard, a dropper/exfil signal.
DATASET.EMBEDDED_PAYLOADA weaponized payload string inside an embedded pickle found in a dataset shard.
DATASET.MALICIOUS_CONTENTA dataset row itself contains a live attack payload, training on it teaches the model to reproduce it.
DATASET.UNSAFE_COMPLETIONAn instruction/response pair whose response is working attack code, a poisoned fine-tuning example.
DATASET.LOADER_NETWORKA loader script makes outbound network calls (requests, urllib, raw sockets), exfiltration or download-exec.
DATASET.LOADER_UNSAFE_DESERIALIZEA loader unpickles / torch.loads / yaml.loads untrusted data, a second code-execution vector.
DATASET.LOADER_DYNAMIC_IMPORTA loader imports a module named by a runtime string (__import__), hiding what it actually pulls in.
DATASET.LOADER_FS_DESTRUCTIVEA loader deletes files or recursively removes directories (shutil.rmtree).
FORMAT.LFS_POINTER_UNRESOLVEDA file is an unresolved Git LFS pointer, the real content was never fetched, so "clean" is meaningless.
ENGINE.FETCH_FAILEDAn artifact could not be fetched, so it was not inspected, surfaced as a finding so it can't slip through as clean.
INTEGRITY.SOURCE_DIGEST_MISMATCHDownloaded bytes don't match the digest the source advertised, possible tampering in transit.
INTEGRITY.MANIFEST_MISMATCHA file's SHA-256 doesn't match its entry in your known-good manifest.
MCP.SERVER_SHELL_PAYLOADAn MCP server manifest launches via a curl | sh-style command, arbitrary code fetched and run at client startup.
MCP.SERVER_REMOTE_CODE_FETCHAn MCP server manifest fetches code from a URL at launch time.
PROMPT.INJECTED_INSTRUCTIONAn agent-readable document contains text that overrides prior instructions, demands concealment, or steers credentials outward.
AGENT.CODE_EXECUTION_TOOLA shell or Python-REPL tool is handed to an agent, a general-purpose execution surface by design.
AGENT/MCP.TOOL_POISONINGA tool's docstring or parameter description carries directive text the LLM reads as instructions, including base64-encoded directives, decoded before matching.
AGENT/MCP.TOOL_HIDDEN_INSTRUCTIONSA tool's description hides text in invisible Unicode (zero-width characters, homoglyphs), readable to the LLM, invisible to a reviewer.
AGENT.TOOL_CREDENTIAL_ACCESSAn LLM-callable tool reads a credential file (an SSH private key, a cloud config), an LLM-controlled path to secrets.
AGENT/MCP.TOOL_SQL_INJECTIONA tool parameter reaches a database query, the LLM authors SQL that runs unparameterized.
AGENT/MCP.TOOL_SSRFA tool parameter becomes the target of an outbound request, an LLM-directed SSRF vector.
AGENT/MCP.TOOL_UNSAFE_DESERIALIZEA tool parameter is deserialized with a pickle-family loader, a second code-execution path through the tool layer.
AGENT/MCP.TOOL_FILE_WRITEA tool parameter is written to or deletes the path it names, LLM-directed filesystem control.
AMARA.HIDDEN_SOURCE_CHARACTERSBidirectional-override or Unicode tag-block characters in source, a "Trojan Source" attack where the rendered text and the parsed order diverge. AMARA decodes and prints what was hidden.
AMARA.OBFUSCATED_PAYLOADA decoded (base64/split-literal) string resolves to a download-and-execute or reverse-shell payload, the obfuscation itself is the tell.
MCP.CONFIG_PROMPT_INJECTIONAn MCP server's description/instructions text contains directive language read by the LLM as instructions.
MCP.CONFIG_HIDDEN_INSTRUCTIONSAn MCP manifest hides text in invisible Unicode inside a field the LLM will read.
PICKLE.UNKNOWN_GLOBALA pickle references a global that isn't on the known-safe allowlist, suspicious by default.
PICKLE.UNRESOLVED_GLOBALA dynamically-constructed global reference that couldn't be resolved to a concrete callable.
PICKLE.TRAILING_DATAExtra bytes after the pickle's STOP, a classic way to hide a second, malicious pickle (which AMARA then also scans).
PICKLE.PARSE_ERRORA malformed pickle stream, often an evasion attempt rather than corruption.
ONNX.CUSTOM_OPERATOR_DOMAINA non-standard custom operator domain, outside ONNX's audited op set.
TFLITE.CUSTOM_OPA TFLite custom operator that needs a native plugin registered by the host to run.
ARCHIVE.HIGH_COMPRESSION_RATIOA member whose compression ratio signals a decompression bomb.
ARCHIVE.OVERSIZED_MEMBERAn archive member far larger than expected, resource-exhaustion risk.
DATASET.PIIRows contain personal data, emails, US SSNs, Luhn-valid card numbers, cloud keys, or private-key blocks.
DATASET.LABEL_ANOMALYA degenerate or severely imbalanced class distribution, how a small poisoned subset often hides.
DATASET.BACKDOOR_TRIGGERA rare token almost perfectly correlated with one non-majority label, the statistical signature of a planted trigger.
DATASET.LOADER_FS_WRITEA loader opens a file for writing outside its own cache, a read-only loader shouldn't touch your disk.
INTEGRITY.NOT_IN_MANIFESTA fetched file isn't listed in the provided manifest of known-good digests.
MCP.SERVER_DANGEROUS_FLAGAn MCP server launch command passes a sandbox-defeating flag.
MCP.SERVER_UNPINNED_PACKAGEAn MCP server launches an npx/uvx package without a pinned version.
MCP.SERVER_AUTO_APPROVEAn MCP manifest pre-approves tool calls (autoApprove / alwaysAllow), skipping the human-in-the-loop check.
MCP.SERVER_HARDCODED_SECRETAn API key or credential is pasted directly into an MCP server's env block.
LLM.HARDCODED_API_KEYA provider API key is hardcoded in source rather than loaded from the environment or a secret store.
LLM.UNTRUSTED_INPUT_IN_PROMPTUntrusted content is concatenated directly into a prompt template.
LLM.DYNAMIC_PROMPT_TEMPLATERetrieved or untrusted text is concatenated into the prompt template itself, not just a variable slot.
AMARA.DYNAMIC_DISPATCHA call target is assembled at "runtime" from __import__ plus a joined string literal instead of named directly, AMARA folds the pieces and names the function that would actually be called.
AGENT/MCP.TOOL_PATH_TRAVERSALA tool parameter is opened for reading as a path, an LLM-chosen filename with no containment check.
LLM.TLS_VERIFY_DISABLEDCertificate verification is disabled (verify=False) on traffic to or from the LLM, a man-in-the-middle vector for prompts and completions.
FORMAT.CODE_EXECUTION_RISKThe artifact is a pickle-family format that can execute code on load, prefer safetensors for untrusted models.
FORMAT.DATASET_SCRIPTAn executable Python loading script is present; its code runs under trust_remote_code.
DATASET.PROVENANCE_UNPINNEDA dataset was fetched from a remote source without a pinned revision, unreproducible and silently re-poisonable.
DATASET.VERBATIM_DUPLICATIONLong text repeated verbatim across many rows, a memorization / verbatim-copy heuristic.
DATASET.SPECTRAL_OUTLIERSpectral-signature outliers in the embedding space (Tran et al.), candidate poisoned samples for review.
DATASET.LOADER_OBFUSCATIONA loader uses base64/codecs decoding, often to hide a payload string from a casual reader.
ARCHIVE.SUSPICIOUS_NAMEA hidden or control-character member name designed to mislead.
ARCHIVE.CORRUPTAn archive that could not be parsed, a coverage gap, not a clean result.
*.COVERAGE_GAP / *.PACKAGE_NOT_INSTALLED / *.ERRORAn operational family (ONNX/Keras/TFLite/engine/app-scan): a check couldn't run, reported explicitly so a skipped scan never looks like a passing one.
FORMAT.DETECTEDThe identified on-disk format and its base risk, the context every other finding hangs off.
INTEGRITY.SHA256Records the artifact's SHA-256 for the audit trail and the Data-BOM.
DATASET.FEATURE_OUTLIERDistance-based outliers in feature space, a dependency-free, influence-style triage signal.
DATASET.SEMANTIC_COVERAGE_GAPNo embedding matrix was present, so poison/spectral scoring couldn't run, stated, not silently skipped.
MCP.SERVERS_DECLAREDRecords which MCP servers a manifest declares, audit-trail context for the findings around them.
Findings alone aren't a decision. The policy engine collapses every finding into one of three verdicts, strictest-wins, and that verdict becomes the exit code your pipeline gates on.
Default policyBlock on any high or critical finding; quarantine on medium; allow otherwise. Override it
wholesale with --policy pointed at your own YAML rules
over severity, finding ID, scanner, or count.
Why fail-closed: rule order can never weaken the outcome, a later, looser rule cannot downgrade a verdict a stricter rule already reached.
Exit codes0, scan completed, nothing at or above --fail-on (or --fail-on wasn't given).1, scan completed, a finding met or exceeded --fail-on.2, the scan itself errored: a bad target, connector failure, or an invalid policy/manifest file.Why it matters: 1 and 2 mean different things
to a pipeline, 1 is "the gate did its job," 2 is "the gate never
ran." Alert on them differently.
SARIF outputFindings rendered as SARIF 2.1.0 for direct upload to GitHub code scanning or any other
SARIF-aware dashboard via --format sarif --output results.sarif.
Data-BOMA provenance manifest, source, revision, and per-file format/size/SHA-256, written with
--data-bom bom.json. Diff it between runs to catch a
dataset or model that drifted underneath a pinned reference, or one that was fetched
unpinned in the first place.