andas

command module
v1.15.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 21, 2026 License: MIT Imports: 2 Imported by: 0

README

andas

ci release license

Most security scanners bury you in alerts. andas answers the question they don't: is this risk actually real for your project, or is it noise?

  • A detected secret is only an emergency if it's still live. andas asks the provider — safely, read-only — and demotes dead credentials out of your way.
  • A CVE in an npm dependency only matters if that package is reachable from your app's own code. andas traces your imports and demotes vulnerabilities in packages nothing imports, and in dev dependencies that never ship.

andas finds four kinds of real risk: leaked secrets (still live?), vulnerable dependencies (does your code reach it?), dangerous code in your own source (SAST), and insecure infrastructure config (Dockerfiles, docker-compose, GitHub Actions). One dependency-free binary. Linux, macOS, Windows.

Install

Grab a prebuilt binary from the latest release:

# macOS (Apple Silicon) example
curl -sSL -o andas https://github.com/malandas/andas/releases/latest/download/andas-darwin-arm64
chmod +x andas && ./andas version

With a Go toolchain:

go install github.com/malandas/andas@latest
# or from a clone:
go build -o andas .

Usage

andas scan                    # scan the current directory
andas scan ./myproject        # scan a specific path
andas scan . --history        # also sweep git history for removed secrets
andas scan . --html out.html  # write a shareable HTML report
andas scan . --sarif r.sarif  # SARIF for CI / GitHub code scanning
andas scan . --json           # machine-readable output
andas scan . --offline        # no network calls at all
andas image myimg.tar         # scan a docker-saved image for vulnerable OS packages
Adopting on a repo that already has debt
andas scan . --baseline andas-baseline.json --update-baseline  # accept today's state
andas scan . --baseline andas-baseline.json                    # now only NEW risk fails CI
Guard your commits
andas hook install     # installs a git pre-commit hook
andas hook status      # is it installed?
andas hook uninstall   # remove it

The hook runs andas scan . --offline --since HEAD --fail-on medium before every commit, so a hardcoded secret is caught before it enters history — which is the leak you can never fully undo. Override a false positive with git commit --no-verify.

Ignoring paths

Drop an .andasignore in the repo root, one pattern per line (like .gitignore): a path segment (testdata, src/generated), a glob (*.min.js), or a # comment. Matching files are skipped by the working-tree scanners.

Flags
Flag Default Meaning
--history off Also scan the full git history for secrets removed from HEAD.
--licenses off Flag dependency licenses with legal obligations (needs installed deps).
--since <ref> Only report findings in files changed since a git ref (fast PR scans).
--baseline <path> Suppress findings recorded in this baseline file.
--update-baseline off Accept all current findings into --baseline, then exit.
--no-entropy off Disable entropy-based detection of unknown/custom secrets.
--html <path> Write a self-contained HTML report.
--sarif <path> Write a SARIF 2.1.0 report for CI / code scanning.
--markdown <path> Write a PR-comment-style Markdown report.
--sbom <path> Write a CycloneDX SBOM of all resolved dependencies.
--no-validate off Skip live validation of secrets.
--offline off Make no network calls at all (no validation, no OSV lookup).
--json off Emit JSON instead of the table.
--no-color off Disable coloured output.
--timeout 8 Per-validation network timeout (seconds).
--fail-on high Exit non-zero when real risk reaches this level.

Exit code is non-zero when the real risk reaches --fail-on, so you can gate a CI pipeline on live secrets while ignoring dead ones.

How the real-risk score works

Every finding carries two levels:

  • Severity — the theoretical/pattern-based level (what other tools give you).
  • Real risk — after andas's context check:
    • secret verified live → promoted to CRITICAL
    • secret verified dead → demoted to INFO (this is the noise we remove)
    • couldn't verify → keeps its theoretical severity

What live validation actually does

For each secret type with a validator, andas sends one read-only request to that credential's own provider (e.g. GET api.github.com/user) and reads the HTTP status: 2xx = live, 401/403 = dead. It never writes, and never sends a secret anywhere except its legitimate provider. Use --no-validate for a fully offline scan.

Validators today: GitHub (PATs + OAuth/App tokens), GitLab, Slack, Stripe, npm, SendGrid, Telegram, OpenAI, DigitalOcean, Mailgun, Figma, Notion, Airtable, Postman, Dropbox, and the paired ones — AWS (an AKIA… key + a nearby secret, proven with a signed STS GetCallerIdentity) and Twilio (an AC… SID + a nearby auth token). Detection-only: Google, private-key blocks.

andas is strictly read-only. It scans files and makes only read-only requests to a credential's own provider — it never edits your code, rotates keys, or opens PRs. It shows you the risk and the fix; the action stays with you.

Beyond these known shapes, an entropy heuristic catches custom/internal secrets: a high-randomness value assigned to a secret-looking name (*token*, *apiKey*, *password*, …). These are unverifiable, so they report as MEDIUM — and if one is a false positive, --baseline silences it for good.

Blast radius — how much can a live secret actually do?

A live secret is critical, but a live admin secret is a five-alarm fire. Because andas is already talking to the provider, it reads back the credential's identity and permissions and flags the dangerous ones:

CRITICAL  GitHub Personal Access Token
          src/ci/deploy.js:8   ghp_••••••yz
          ▲ VERIFIED LIVE — rotate this credential now
          identity: octocat
          🔓 can access: repo, admin:org, workflow
          ⚠ HIGH-PRIVILEGE credential — maximum blast radius
  • GitHub → OAuth scopes (repo, admin:org, delete_repo, …)
  • GitLab → personal-access-token scopes (api, sudo, …)
  • SendGrid → API-key scopes (mail.send, admin scopes)
  • AWS → the identity ARN and account, root/admin flagged
  • Stripe / npm → full-access keys flagged as privileged

High-privilege live secrets sort to the very top of the report — same severity, bigger blast radius.

Exposure timeline & attack path

Two more read-only signals that turn a list of findings into a real picture:

  • Exposure timeline — from git blame (and commit dates for history leaks), andas tells you how long a secret has been exposed: ⏱ exposed ~47 days (since 2025-11-08). A key leaked months ago is a different emergency from one added today.

  • Attack path — andas narrates how the confirmed findings chain together:

    ⚔ attack path
       • A live, high-privilege AWS (arn:…:root) is exposed — an attacker gains account access.
       • Multiple live credentials are exposed together (AWS, GitHub) — one leaked repo hands an attacker all of them.
       • A credential removed from the code is still live in git history — deleting the line never rotated the key.
    

    Every line is grounded in something andas actually verified — never invented risk.

Dependency scanning — many languages

andas scans dependency manifests across ecosystems and cross-references every package against OSV.dev:

Language Manifest Reachability
JavaScript / TypeScript package.json + package-lock.json / yarn.lock ✅ import-level + used symbols
Python requirements.txt (pinned) ✅ import-level
Go go.mod ✅ import-level
Ruby Gemfile.lock ✅ import-level
Rust Cargo.lock ✅ import-level
PHP composer.lock ✅ import-level

All six ecosystems now get the same real-risk filter: andas parses your source and demotes a vulnerability in any package your code never imports. For all six languages, andas also reports which functions of a vulnerable package your code actually calls (↳ your code uses: safe_load). Each language.s import mechanism is handled honestly — Python resolves distribution→module aliases (PyYAMLyaml); Go matches a module or any of its subpackages; Rust maps Cargo hyphens to use underscores; PHP reads each package's PSR-4 namespace from composer.lock and matches use statements; Ruby falls back to treating all gems as reachable when it sees Bundler.require (which auto-loads everything), so a used gem is never wrongly cleared.

Reachability, in depth (JS/TS)

For a project with a package.json, andas also:

  1. Reads package.json plus a lockfile — package-lock.json (npm) or yarn.lock (Yarn v1 and Berry/v2+) — to resolve the full dependency tree with exact versions. With no lockfile it falls back to direct dependencies.
  2. Queries OSV.dev (free, no API key) for known vulnerabilities in each package.
  3. Parses your .js/.jsx/.ts/.tsx source to see which packages you actually import, then walks the graph to compute what's reachable. A vulnerable package outside that set — an unused transitive dep, or a dev-only tool that never ships in your React Native bundle — is demoted to LOW.

Reachability is at the import level (is the package reached at all). As a first step toward function-level reachability, andas also reports which exports of a vulnerable package your code actually uses (↳ your code uses: merge, template) — evidence for triage. It deliberately does not downgrade on this signal: mapping an advisory to exact functions is unreliable, and a false "safe" is worse than a false alarm.

Git-history secret scanning (--history)

The sharpest edge. A credential deleted from your latest commit still lives in git history — and history is public the moment the repo is. With --history, andas sweeps every blob across all branches and commits, and — because it validates live — reports the case that actually matters:

CRITICAL  AWS Access Key ID (in git history)
          git history @ 4f1a9c2 (Sara N., 2025-11-08)   AKIA••••••7Q
          ▲ removed from HEAD but still recoverable — AWS accepted the key pair — LIVE
          → fix: Deactivate the key in IAM → Security credentials, then create a fresh pair.

Secrets still in the working tree are left to the normal file scan; --history reports only the ones that were removed but never rotated.

Static analysis of your own code (SAST)

Beyond secrets and dependencies, andas scans your own source for dangerous patterns — code injection (eval), OS command execution, unsafe deserialization, path traversal, SSRF, weak crypto (MD5/SHA1, insecure randomness), XXE, template injection (SSTI), open redirect, NoSQL injection, disabled TLS, XSS, and SQL injection, plus broken JWT verification, insecure cookies, hardcoded crypto keys, disabled CSRF, world-writable files, weak TLS, LDAP/XPath injection, prototype pollution, mass assignment, and regex-from-input (ReDoS) — 27 CWE classes across JS/TS, Python, Ruby, PHP, and Go, each tagged with its CWE. The rules are tight and high-signal, and every finding notes whether user-controlled input reaches it — either directly on the line (req.query, $_GET, request.args, …) or through a variable assigned from user input earlier in the same function. andas follows that with a light intra-procedural taint tracker, so a dangerous sink is flagged as user-reachable even when the source is several lines above it. It only ever raises a finding's confidence, never lowers it. Comment lines and minified/generated code are skipped to keep false positives down.

Infrastructure & CI config (IaC)

andas also scans the config files every repo ships with:

  • Dockerfiles — running as root, :latest base images, ADD from a URL, curl ... | bash, chmod 777.
  • docker-composeprivileged: true, the Docker socket mounted into a service, host networking.
  • GitHub Actions — script injection via ${{ github.event.* }} in run:, pull_request_target, third-party actions pinned to a moving branch.
  • Terraform — security groups open to 0.0.0.0/0, public bucket ACLs, encryption disabled, hardcoded credentials.
  • Kubernetes — privileged containers, host namespaces, run-as-root, privilege escalation allowed.

Reports & CI

  • --html <path> — a self-contained, theme-aware HTML report you can share.
  • --sarif <path> — SARIF 2.1.0; the level of each result is driven by real risk, so a dead secret lands as a note and a live one as an error. Upload it with github/codeql-action/upload-sarif to populate the Security tab.
  • --markdown <path> — a compact, PR-comment-style summary. andas only writes the file; posting it (if you want) is your CI's job — andas stays read-only.
  • Every finding carries a concrete fix line (rotation link, upgrade target).

A ready-to-use workflow is in examples/github-workflow.yml.

License compliance

andas scan . --licenses reads the licenses of your installed dependencies (node_modules for npm, *.dist-info for Python) and flags the ones with legal obligations — strong copyleft (GPL/AGPL) and missing/unknown licenses. It auto-detects whether your project is proprietary (a private or UNLICENSED package.json) or open-source and scores accordingly: an AGPL dependency is a HIGH obligation for a closed product but merely informational for an OSS one. Permissive licenses (MIT, BSD, Apache) are treated as noise.

SBOM (Software Bill of Materials)

andas scan . --sbom bom.json writes a CycloneDX 1.5 SBOM of every dependency it resolves across all six ecosystems — with correct package URLs (pkg:npm/lodash@4.17.11, pkg:pypi/Django@2.2.0, pkg:golang/…, …). Since andas already resolves the full graph to scan it, the SBOM is the same data in the standard format vendors, dashboards, and regulators expect.

Configuration

Drop an optional .andas.yml in the repo root to tune a scan without flags:

fail-on: critical      # default gate level
disable:               # silence specific rules by id
  - docker-latest-tag
  - gha-unpinned-action
ignore:                # extra ignore globs (merged with .andasignore)
  - testdata

Scanners run concurrently, so on a large repo the total scan time is roughly the slowest single scanner rather than the sum of all of them.

Development

go build -o andas .   # build
go test ./...         # run the test suite
go vet ./...          # static checks

The suite covers the security-critical logic directly: the real-risk decision table, entropy precision (it must catch real secrets and reject placeholders), the npm/Yarn (v1 + Berry) lockfile parser, the reachability BFS, the blast-radius scope parsers, the baseline round-trip (which must never persist raw secret material), plus end-to-end tests of the CLI wiring and the git-history scanner. CI runs vet + test and has andas scan its own source on every push.

See CHANGELOG.md for the release history.

Status

v1.8.0 (SAST now follows a light intra-procedural taint flow) — five scanners on one real-risk core: secrets (17 live validators), dependencies (6 ecosystems, reachability + function-level), git history, SAST, and IaC/CI config (Dockerfile, docker-compose, GitHub Actions), on one real-risk core with blast-radius scoring, exposure timeline, attack-path narrative, entropy detection, baseline, a pre-commit guard, four report formats, and a 48-test suite. Strictly read-only:

Scanner Detects Context that separates signal from noise
secrets 12 credential types live validation across 8 providers (incl. signed AWS STS)
deps npm/Yarn vulns (v1 & Berry) import reachability + which vulnerable functions your code calls
git-history secrets removed from HEAD still-in-history and still-live

Outputs: terminal, JSON, HTML, SARIF — each with remediation.

License

MIT — see LICENSE.

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
Package cmd wires the andas command-line interface.
Package cmd wires the andas command-line interface.
internal
config
Package config loads an optional .andas.yml from the scan root so a team can tune andas without touching flags: silence rules that don't apply, add ignore globs, and set the default fail-on level.
Package config loads an optional .andas.yml from the scan root so a team can tune andas without touching flags: silence rules that don't apply, add ignore globs, and set the default fail-on level.
finding
Package finding defines the unified result model shared by every scanner.
Package finding defines the unified result model shared by every scanner.
gitmeta
Package gitmeta reads read-only metadata from git — never writes — so andas can tell you *how long* a secret has been exposed.
Package gitmeta reads read-only metadata from git — never writes — so andas can tell you *how long* a secret has been exposed.
license
Package license classifies dependency licenses and flags ones that carry obligations a typical closed-source product can't meet — strong copyleft (GPL/AGPL), or a missing/unknown license (which legally means "no rights granted").
Package license classifies dependency licenses and flags ones that carry obligations a typical closed-source product can't meet — strong copyleft (GPL/AGPL), or a missing/unknown license (which legally means "no rights granted").
osv
Package osv is a small client for OSV.dev, shared by the dependency scanner and the container-image scanner.
Package osv is a small client for OSV.dev, shared by the dependency scanner and the container-image scanner.
report
Package report renders findings for humans and machines.
Package report renders findings for humans and machines.
sbom
Package sbom generates a Software Bill of Materials in CycloneDX 1.5 JSON — the format most vendors, regulators, and dependency dashboards ingest.
Package sbom generates a Software Bill of Materials in CycloneDX 1.5 JSON — the format most vendors, regulators, and dependency dashboards ingest.
scanner
Package scanner defines the contract every detector implements, plus the shared file-walking machinery so each scanner doesn't reinvent it.
Package scanner defines the contract every detector implements, plus the shared file-walking machinery so each scanner doesn't reinvent it.
scanner/deps
Package deps scans JavaScript/TypeScript projects for vulnerable npm dependencies and — andas's differentiator — decides whether each vulnerable package is actually reachable from the app's own code before ranking it.
Package deps scans JavaScript/TypeScript projects for vulnerable npm dependencies and — andas's differentiator — decides whether each vulnerable package is actually reachable from the app's own code before ranking it.
scanner/githistory
Package githistory scans a repository's entire git history for secrets — not just the current working tree.
Package githistory scans a repository's entire git history for secrets — not just the current working tree.
scanner/iac
Package iac scans infrastructure-as-code and CI config — Dockerfiles, docker-compose, and GitHub Actions workflows — for insecure settings.
Package iac scans infrastructure-as-code and CI config — Dockerfiles, docker-compose, and GitHub Actions workflows — for insecure settings.
scanner/image
Package image scans a container image tarball (`docker save -o img.tar …`) for vulnerable OS packages.
Package image scans a container image tarball (`docker save -o img.tar …`) for vulnerable OS packages.
scanner/licenses
Package licenses scans the licenses of installed dependencies and flags ones that carry legal obligations — strong copyleft in a proprietary product, or a missing license.
Package licenses scans the licenses of installed dependencies and flags ones that carry legal obligations — strong copyleft in a proprietary product, or a missing license.
scanner/sast
Package sast statically scans the user's *own* source for dangerous code patterns — code injection, command execution, unsafe deserialization, and so on.
Package sast statically scans the user's *own* source for dangerous code patterns — code injection, command execution, unsafe deserialization, and so on.
scanner/secrets
Package secrets detects hardcoded credentials and — andas's differentiator — verifies whether each one is still live before deciding how loud to be.
Package secrets detects hardcoded credentials and — andas's differentiator — verifies whether each one is still live before deciding how loud to be.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL