Skip to content

What's new

A version-by-version history of Fendix. v3.7.0 shipped October 2026: the GitHub Action fails the job when Semgrep cannot run, and a fatal Semgrep run is recorded as failed instead of passing as a clean scan. Each entry below lists what changed in that release.

Product update · November 1, 2026

Decision Intelligence: beyond the scan

Decision Intelligence brings release verdicts, Decision History, Scan Comparison, evidence-backed shared remediation points and recommended next actions into one workspace journey. Coverage and comparability stay visible, and human-reported fixes remain distinct from verification. No automatic code changes.

Explore Decision Intelligence

The GitHub Action fails closed when a required analyzer cannot run

October 2026

  • An unavailable required analyzer can no longer produce a green release gate. Until v3.6.5, a self-hosted runner whose Semgrep could not scan passed the gate: on glibc older than 2.34, pip built Semgrep from source without semgrep-core, the scan recorded Semgrep as failed and coverage as incomplete, and the job still went green. The Action now requires Semgrep for every code scan through a new require-analyzers input (default auto). Before the scan it runs the scan's own Semgrep offline on a bundled rule and requires the known match, and it passes the requirement to the engine as --require-analyzers. A missing, damaged, crashing or hung Semgrep fails the job with exit 2, and extra-args cannot cancel the requirement.
  • No source builds, no partial uploads, no misleading success. The Action installs the engine's Python packages from wheels only. A package with no wheel for the runner stops setup with exit 2 and names the runner's C library, its version, the architecture and the supported floor. SARIF goes to code scanning only when the scan finished (exit 0 or 1), so a failed scan no longer closes alerts. The clean-scan line needs a finished scan, delivered required analyzers and complete coverage; anything else is a warning or an error that names the gap.
  • A fatal Semgrep run is recorded as failed, not as a clean scan. In every integration, a Semgrep that was killed mid-run (out of memory, for example), hit a rule that does not parse or had an invalid config used to be recorded ok with no findings. It is now failed, so --require-analyzers semgrep, --fail-on-coverage-gap and --fail-on-scanner-error exit 2 on it, and a hosted scan's decision is incomplete instead of a pass. Per-file problems, such as a file that does not fully parse or a per-file timeout, leave the run ok and are counted in the scanner detail. Findings Semgrep printed before it failed stay in the report. The accuracy corpus result is byte-identical to v3.6.5.
  • Upgrading. Self-hosted Linux runners with glibc older than 2.34 (Ubuntu 20.04, Debian 11, RHEL 8 and its rebuilds, Amazon Linux 2) now fail code scans at setup. Run Fendix in the official image as a container job, move the runner to glibc 2.34 or later, or set require-analyzers: none to scan without Semgrep; the gate then warns that coverage is not enforced. extra-args: --fast now fails a code scan unless the requirement is relaxed. The native CLI keeps its defaults, and report schema, SARIF structure, fingerprints, decision policy and the meaning of each exit code are unchanged. Fendix-app/Fendix@v1 resolved to the v3.6.2 Action at release; it was moved to the v3.7.0 release commit on 2026-10-27, so @v1 and the pinned commit now run the same fail-closed Action. Hosted scans run v3.7.0.

Semgrep 1.182.1 and MCP 1.29.0 fix the last fixable HIGH advisories

October 2026

  • The remaining fixable HIGH advisories in the official image are fixed. golang.org/x/mod 0.40.0 in the fendix binary fixes two checksum-database verification bypasses (GO-2026-6180, GO-2026-6179). MCP 1.29.0, which comes with Semgrep 1.182.1, fixes three MCP SDK server advisories (CVE-2025-66416, CVE-2026-52869, CVE-2026-59950); Fendix never starts Semgrep's MCP server, and the package is upgraded wherever it ships. The image also applies the Debian security updates published since its base image, and its HIGH findings fall from 102 to 44, every one of them in a Debian package with no fix published.
  • Semgrep no longer contacts semgrep.dev. Every Semgrep run used to ask semgrep.dev whether a newer Semgrep existed, --offline included. Fendix now turns that check off. Offline, the check waited before the scan started, up to about 96 seconds with Semgrep 1.182.1, which could time Semgrep out on a mid-size repository.
  • Semgrep 1.182.1, with no measured change in findings. On the accuracy corpus, matches, titles, fingerprints and statuses are byte-identical to v3.6.4: 38 true positives, 0 false positives, 0 false negatives and 18 true negatives. The official image now installs its Python packages from the same hash-locked file the GitHub Action installs, so both run identical versions.
  • Self-hosted Linux CI runners need glibc 2.34 or later for Semgrep. No Semgrep release with the MCP fix supports an older glibc. On Ubuntu 20.04, Debian 11, RHEL 8 and its rebuilds, or Amazon Linux 2, the scan still runs, but it records Semgrep as failed and coverage as incomplete, and the gate is decided by the analyzers that ran. Use the official image or a newer runner, or add extra-args: --require-analyzers semgrep to fail the job instead. GitHub-hosted runners and the official image are not affected.
  • Upgrading. Nothing to migrate. No report-schema, SARIF, fingerprint, decision-policy or exit-code change. Fendix-app/Fendix@v1 is unchanged; its default version: latest installs this release, and version: v3.6.5 pins it. Hosted scans run v3.6.5.

TLS no longer trusts the compromised emSign intermediates

October 2026

  • The compromised emSign intermediates are no longer trusted. Eight eMudhra intermediate CAs that chain to emSign ECC Root CA - G3 had their private keys compromised and have been revoked. Anyone holding one of those keys and on the network path could present a valid-looking certificate for any host the engine connects to. The fendix binary is now built with Go 1.27.3, whose crypto/x509 rejects those intermediates (GO-2026-6809), and certifi 2026.10.23, which drops the affected root (GHSA-6q48-6c7w-9gw2), is in the image's Python environment and in the hash-locked engine install the GitHub Action uses.
  • An HTTP/2 scan target can no longer burn the scanner's CPU. Go 1.27.1's HTTP/2 client spent excessive CPU when a peer opened many streams and then sent many small SETTINGS_INITIAL_WINDOW_SIZE frames (CVE-2026-78669, fixed in Go 1.27.2). The engine negotiates HTTP/2 with the targets it scans, so a hostile target could stall a URL scan. Go 1.27.3 includes that fix, and fixes for unbounded Range header parsing in net/http (CVE-2026-78667) and malformed ECH extensions in crypto/tls (CVE-2026-97031).
  • govulncheck in the official image judges the standard library at Go 1.27.3. It reports standard-library advisories against the bundled toolchain, so a Go module scanned with the image can report fewer standard-library findings than with v3.6.3: code that reaches x509.Certificate.Verify is no longer reported as affected by GO-2026-6809. A standalone binary uses the go on your PATH, so its results do not change.
  • Upgrading. Nothing to change. No scanner, rule, fingerprint, report-schema, SARIF, decision-policy or exit-code change, so baselines, .fendix-ignore rules and SARIF alerts carry over. Fendix-app/Fendix@v1 is unchanged; its default version: latest installs this release, and version: v3.6.4 pins it. Hosted scans run v3.6.4.

Four Semgrep rules match, and the Flask advice protects the route

October 2026

  • The Flask auth advice was inverted. flask-route-no-auth-decorator said the auth decorator belongs directly above @app.route(...). Flask's route() must be the outermost decorator, so following that advice left the route unauthenticated. The finding's fix text, its SARIF help and the check catalog now say the decorator goes directly below @app.route(...), and that one placed above it does not protect the route.
  • Four bundled Semgrep rules now match. python-eval-injection, python-jwt-decode-no-verification, python-sql-injection-string-format and python-command-injection-shell-true listed alternative patterns that all had to match at once, so none of them ever fired. They now detect eval() or exec() with a non-literal argument, jwt.decode() with signature verification disabled or the "none" algorithm, an execute() query built with %, +, an f-string or .format(), and os.system() or os.popen() with a non-literal command. jwt.decode(..., algorithms=["none"]) was caught by no analyzer before.
  • They report; by default they do not block. The new findings carry their rule severity, CRITICAL or HIGH. Under the default confidence-gated --fail-on, a Semgrep finding without corroboration stays in the MEDIUM confidence band and its disposition is WARN, so the repaired findings do not BLOCK. A scan that was PASS can now be WARN when one of these rules reports. The verified hosted case, JWT decoding with signature verification disabled, is CRITICAL severity, WARN disposition and release decision WARN. With --enforce-confidence=false, the legacy severity-only gate, they block at or above the threshold and are marked policy_override.
  • The check catalog has static copy for eleven rules. Titles and remediation that printed raw Semgrep metavariables such as '$VAR' now read as fixed text; findings still name the matched symbol. No title, fingerprint, grouping key, baseline entry or .fendix-ignore match changes.
  • The GitHub Action is listed on GitHub Marketplace as Fendix Security Scan. Fendix-app/Fendix@v1 points to the v3.6.2 release commit, which passed the external end-to-end matrix, and is the recommended GitHub integration; the Action itself is unchanged. Set version: v3.6.3 to install this release. Hosted scans run v3.6.3.

Diff-aware scans read the changed files, however the path is written

October 2026

  • A relative `--code` no longer empties a diff-aware scan. In diff mode (--diff, --staged) with a relative path such as ., Semgrep and the native text scanner scanned none of the changed files while the coverage table reported both as ok. A relative and an absolute --code now scope the same files and report the same findings. The secrets scanner and the Python engine were not affected.
  • The Action's pull-request check and the pre-commit hook see those findings again. With code: . and diff: auto, a pull request adding a privileged Kubernetes container passed with zero findings; it now blocks, as it already did with an absolute path. The hook fendix hook install writes now rejects a commit that stages that manifest.
  • A diff scope that cannot be represented safely becomes a full scan. When a changed file cannot be placed under the scan root, the scan says so and scans --code in full, as it already did when git diff fails; it never narrows to nothing. Until diff scoping supports it, a diff-mode scan with --code set to a subdirectory also scans that directory in full.
  • Upgrading. Pull requests and commits can now report findings, and block, where v3.6.1 passed; these are findings v3.6.1 should have reported. Use a baseline to report only new findings. The v3.6.1 workarounds, an absolute code path or diff: 'false', still work and can be removed. No report-schema, SARIF, fingerprint or exit-code change. Hosted scans stayed on v3.6.0 and moved to v3.6.3 directly.

The GitHub Action verifies the release before it runs it

October 2026

  • SARIF for a scan with no findings is valid. The exporter wrote "rules": null, which SARIF 2.1.0 forbids and GitHub's SARIF upload rejects, so a clean scan failed at the upload. fendix scan --format sarif and fendix report --format sarif now write "rules": [].
  • The Action checks the signature before the binary first runs. It installed Fendix before cosign was available, so the install fell back to a checksum and the binary ran unverified. cosign now installs first for every caller, the installer bundled with the Action installs one exact release with the signature required, and the binary must report exactly that release before it is put on PATH. There is no checksum-only fallback, and inherited FENDIX_* variables cannot redirect or weaken the install.
  • The Action works with its defaults and fails closed. Every tag through v3.6.0 failed before scanning when engine_path was left empty. The Python engine is now prepared from source at the commit named by the release's signed build record, with a hash-locked dependency set. Exit 1 is a policy BLOCK, exit 2 a setup or scan error, and any other result fails closed with 2; SARIF is uploaded only when the scan wrote a report.
  • `fendix init --ci gitlab` keeps SARIF as an ordinary artifact instead of declaring it under artifacts:reports:sast, which expects GitLab's own SAST schema.
  • Upgrading. The Action needs outbound HTTPS to Sigstore as well as GitHub and PyPI. SARIF upload from a private or internal repository needs actions: read and GitHub Code Security. The Action no longer installs a release without a cosign signature. The fendix scan report schema, finding policy and exit codes are unchanged. Hosted scans stayed on v3.6.0.

A suppression covers only the occurrence it names

October 2026

  • A baseline or ignore rule can no longer hide a production credential. A finding groups every occurrence of one check, and baselines and .fendix-ignore rules acted on the group, keyed on its first occurrence. A test fixture saved in a baseline, or matched by an ignore rule for **/tests/**, hid a new production credential that grouped with it, and whether it did depended on how the directory names sorted. Each occurrence is now fingerprinted, baselined and ignored on its own before findings are grouped.
  • Findings list their occurrences. Every finding carries occurrences: [{endpoint, fingerprint}], and the report schema_version stays 2. --save-baseline writes baseline format v2, which records every occurrence. Baselines from v3.5.1 or earlier still load, and each entry proves only its own fingerprint and its exact recorded locations.
  • SARIF, Jira and verify follow the occurrence. SARIF emits one result per occurrence with its own partialFingerprints, so a GitHub Code Scanning dismissal covers one occurrence. fendix jira tracks occurrences with fendix-fp: labels, and fendix verify re-tests every occurrence and resolves a grouped finding only when all of them are fixed.
  • Ignore patterns and secret names are exact. **/ matches zero or more directories, so **/tests/** matches a top-level tests/, and * stays within one path segment. A secret is named after the binding that holds it: email="…", password="…" is now named password.
  • Upgrading, once. Re-save baselines with --save-baseline. The first SARIF upload opens a new alert for every non-primary occurrence of a grouped finding, and fendix jira re-files findings that were tracked only by fendix-id: labels. Hosted scans run v3.6.0.

Generated CI installs the release that wrote it

October 2026

  • `fendix init` writes CI that installs Fendix. The generated GitHub workflow ran go install …@latest, which never resolved, and the GitLab and CircleCI files downloaded a tarball current releases do not publish. All three now pin FENDIX_VERSION to the release that generated them, fetch the official installer at that release's commit, so moving a tag cannot swap the script, and require a verified cosign signature. The CircleCI job installs a checksum-pinned cosign first, and all three accept an optional FENDIX_SHA256 pin.
  • `brew upgrade fendix` offers new releases again. Older Homebrew recorded installs as version 64, which current Homebrew ranks above every 3.x release, so those installs were never offered an upgrade. The formula now sets version_scheme 1, which ranks every release above them.
  • The installer can refuse instead of falling back. FENDIX_REQUIRE_SIGNATURE=1 refuses the install when cosign is missing or the release carries no signature, and FENDIX_SHA256 refuses any binary whose hash differs from the pin. Both are opt-in; the default curl … | sh behaviour is unchanged.
  • Organization module path. New binaries report github.com/Fendix-app/Fendix/go in go version -m, stack traces and SBOMs. Remote go install is not a supported installation method.
  • No scanner, fingerprint, report-schema, decision-policy or exit-code changes. Hosted scans run v3.5.1.

v3.7.0 shipped October 2026 — the GitHub Action requires Semgrep for code scans and fails the job when it cannot run, installs wheels only and uploads SARIF only for a finished scan, and a fatal Semgrep run is recorded as failed; no report-schema, SARIF, fingerprint or decision-policy changes, and every exit code keeps its meaning. v3.6.5 shipped October 2026 — Semgrep 1.182.1, MCP 1.29.0 and golang.org/x/mod 0.40.0 fix the last fixable HIGH advisories in the official image, Semgrep no longer contacts semgrep.dev, and self-hosted Linux CI runners need glibc 2.34 or later for Semgrep; no scanner, fingerprint, report-schema, decision-policy or exit-code changes. v3.6.4 shipped October 2026 — rebuilt on Go 1.27.3 and certifi 2026.10.23, so TLS no longer trusts the eight compromised emSign intermediate CAs and a hostile HTTP/2 scan target can no longer burn the scanner's CPU; no scanner, fingerprint, report-schema, decision-policy or exit-code changes. v3.6.3 shipped October 2026 — four bundled Semgrep rules that never matched now report, WARN by default under the confidence-gated --fail-on; the Flask auth advice says the decorator goes below @app.route(...); eleven checks have static catalog copy; no finding-identity change. v3.6.2 shipped October 2026 — diff-aware scans with a relative --code scan the changed files again, and a diff scope that cannot be represented safely falls back to a full scan. v3.6.1 shipped October 2026 — SARIF for a scan with no findings is valid, and the GitHub Action verifies the release signature before it runs the binary. v3.6.0 shipped October 2026 — baselines, .fendix-ignore rules and SARIF act on each security occurrence, so a baselined or ignored test fixture can no longer hide a new production credential grouped with it; baseline format v2, one SARIF result per occurrence, and fendix jira and fendix verify track every occurrence. v3.5.1 shipped October 2026 — fendix init writes CI that installs a pinned, signature-verified Fendix, brew upgrade reaches installs older Homebrew recorded as version 64, and the installer can require a signature or a pinned SHA-256; no scanner, fingerprint, report-schema, decision-policy or exit-code changes. v3.5.0 shipped October 2026 — --fail-on refuses an invalid threshold instead of silently scanning with none, fendix verify no longer reads missing input as a fix, and images publish to Docker Hub; no fingerprint, report-schema or decision-policy changes. v3.4.1 shipped September 2026 — the engine images now ship Go 1.27, raising govulncheck's module ceiling from 1.25; no scanner, fingerprint or exit-code changes, and the Go module floor stays 1.25. v3.4.0 shipped September 2026 — a scan can no longer look complete when it wasn't: every analyzer records whether it ran and why not, the report carries a coverage block that names the gaps, a URL scan with zero endpoints writes its report instead of vanishing, and two opt-in flags turn a coverage gap into a failing build. v3.3.0 shipped September 2026 — an upgrade no longer splits a finding you were already tracking into a closed one and a new one, and the list of checks a scan ran is built from what completed rather than what was configured. v3.2.0 — every blocking decision explains itself. A BLOCK now carries the policy it was made under and the evidence class that justified it, all the way through Fendix's own storage into the SARIF you export, so a failed pipeline is answerable from the report alone. Findings held back say why, confidence scores come with the rules that produced them, and a build blocked only because confidence enforcement was switched off is labelled as such. v3.1.0 stopped findings claiming more than they proved — wildcard CORS with credentials, rate-limit prioritisation, response-aware header grading, path-traversal wording, test-fixture credentials and dependency applicability all became more precise. v3.0 gave findings a stable identity based on which rule fired, in which file, in which function, about which operation. Re-save your baselines once after upgrading from before v3.0, and rewrite any .fendix-ignore rule that pins a fingerprint: value — rules using the supported id, endpoint or category selectors are unaffected by the fingerprint change, although positional SEC-NNN ids are suitable only for short-lived triage.