Product Security

Enhance Software Security with Static Application Security Testing: A Comprehensive Guide

Unlock the power of SAST to secure your software development process. Learn about effective tools, benefits, and best practices for a safer codebase.

Finite State Team

Finite State Team

September 27, 2025

TL;DR

Static application security testing (SAST) analyzes code at rest to find security flaws before a build ships. It works well on the code your team writes and stops at the vendor SDKs, RTOS images, and supplier binaries that make up much of a device image. Both the EU Cyber Resilience Act and FDA's premarket cybersecurity guidance now expect the scan reports as filed evidence, which changes SAST from a developer convenience into a compliance artifact.

What is static application security testing (SAST)?

Static application security testing analyzes source code, bytecode, or binaries for security flaws without executing the program. Security teams call this white-box testing.

The scan runs against code at rest. No test harness, no running device, no network. That property is what lets SAST run on a laptop during development and again on every commit, and it is also the source of every limitation covered further down this page.

What a SAST engine looks for falls into a few families:

  • Injection paths. Untrusted input reaching a SQL query, a shell command, or a rendered page. SQL injection and cross-site scripting sit here.
  • Memory safety errors. Buffer overflows, off-by-one indexing, use-after-free. These dominate findings in C and C++ firmware.
  • Hardcoded secrets. API keys, default passwords, and private keys committed into the tree.
  • Weak cryptography. Deprecated ciphers, fixed initialization vectors, predictable random number generation.
  • Unsafe function use. strcpy, sprintf, gets, and the rest of the list every embedded team knows and still ships.

Findings map to the Common Weakness Enumeration, so a SAST report reads as a list of CWE IDs with file names and line numbers attached.

NIST puts this activity in a specific place. In the Secure Software Development Framework, practice PW.7 is Review and/or Analyze Human-Readable Code, and the framework defines human-readable code as source code, scripts, and any other form a team deems human-readable. Testing the compiled artifact is a separate practice, PW.8. That split matters for anyone building an audit trail, because two different practices need two different pieces of evidence.

How does SAST work in a build pipeline?

A SAST engine parses code into an abstract syntax tree, traces how data and control move through it, then matches those paths against security rules.

Four stages, in order:

  1. Parse. The engine reads the source and builds an abstract syntax tree representing functions, loops, conditionals, and variables.
  2. Trace. Control flow analysis maps the execution paths through the code. Data flow analysis follows values from where they enter to where they get used, which is how a tool connects an unvalidated HTTP parameter to a database call forty lines away.
  3. Match. The engine tests those paths against a rule set. Rules ship with the tool and get extended in-house.
  4. Report. Each finding arrives with a severity, a file, a line, and usually the traced path from source to sink.

Most tools emit SARIF, the Static Analysis Results Interchange Format maintained by OASIS. OWASP lists SARIF support under tool selection criteria for a practical reason: it lets findings from three different scanners land in one review queue instead of three dashboards.

A human stays in the loop. SSDF task PW.7.2 spells this out in its implementation examples, describing a static analysis tool that checks code automatically with a person reviewing the reported issues and remediating them. Automated triage-free SAST is not what the framework describes.

What does SAST find, and what does it miss?

SAST reliably catches injection flaws, buffer overflows, and hardcoded credentials. OWASP documents six weaknesses, led by high false positive rates and unbuildable code.

Start with what works. OWASP credits static analysis with scaling across large codebases, running repeatedly in nightly builds and continuous integration, and pointing at the exact filename, location, and line number of a problem. Millions of lines in minutes, every night, with a pin in the map. Manual code review does not compete on that.

The six documented weaknesses, from the same OWASP page:

  • Many vulnerability classes resist automated detection, specifically authentication problems, access control issues, and insecure use of cryptography.
  • Current tools identify only a relatively small percentage of application security flaws.
  • False positives run high.
  • Configuration issues usually go undetected, because they do not appear in the code.
  • Proving that a flagged issue is a real, reachable vulnerability is difficult.
  • Code that will not compile is hard to analyze, and analysts often cannot compile it without the correct libraries, the compilation instructions, and all the required code.

That last point lands hardest on embedded teams. A cross-compiled build for a custom board, dependent on a vendor toolchain and a header tree that only exists inside one Docker image, is exactly the case OWASP describes.

The false positive rate has an operational cost worth naming plainly. A first full scan on a mature C codebase commonly returns thousands of findings, and a team that treats all of them as a release blocker stops shipping. The CI/CD section below covers how to avoid that outcome.

For the vulnerability classes SAST cannot reach, the answer is other testing. Reachability and exploitability need a running system or a shipped binary, which is where dynamic testing, fuzzing, and binary-level penetration testing do the work that a static scan cannot.

How is SAST different from DAST, IAST, and SCA?

SAST reads code at rest. DAST attacks a running system. IAST instruments the runtime. SCA identifies third-party components. Each reads a different artifact.

The four categories get grouped as "application security testing" and then used interchangeably, which causes real coverage gaps. They read different things:

What it readsWhen it runsPrimary blind spot
SASTSource, bytecode, some binariesCoding and buildConfiguration, runtime behavior, reachability
DASTA running application's exposed interfacesStaging, pre-releaseAnything not exposed through an interface it can reach
IASTRuntime behavior via in-process instrumentationDuring functional or automated testsCode paths the test suite never executes
SCADependency manifests, and in binary SCA the compiled artifactBuild and continuously post-releaseCustom code your own team wrote

SAST and software composition analysis form the most common pairing, and the division is clean: SCA answers "which components are in here and what CVEs do they carry," SAST answers "what did we write badly." A device with zero SCA findings can still ship a hardcoded root password in first-party code.

In a CI/CD pipeline, the timing differs more than the technique. SAST runs on a commit in seconds to minutes and blocks a pull request. DAST needs a deployed, running instance, so it runs later, takes longer, and typically gates a release candidate rather than a merge. A team that tries to run DAST at pull-request speed ends up disabling it.

Which code can SAST reach in a firmware build?

SAST covers the code your team compiles from source. Vendor SDKs, RTOS binaries, and supplier blobs arrive without source, so binary analysis covers them.

This is the question most SAST material skips, and for a device manufacturer it decides how much of the product actually got tested. A shipped firmware image is an assembly of parts with different provenance:

Part of the imageSource available?What reaches it
First-party application codeYesSAST
In-house libraries and shared modulesYesSAST
Open source pulled by the buildUsuallySCA, plus SAST if compiled locally
Vendor SDK and BSPRarelyBinary analysis
RTOS or embedded Linux imagePartiallyBinary analysis
Pre-compiled supplier blobs and ODM componentsNoBinary analysis
Build-time and packaging additionsNo source at allBinary analysis

Run a SAST scan across a device tree and it reports on the first three rows. The bottom four ship untested by that scan, and on many devices they represent the larger share of the image. Source and binary analysis answer different questions, and a firmware program needs both.

NIST anticipates this. SSDF task PW.4.1 lists binary software composition analysis alongside SBOM and source composition analysis as ways to obtain provenance for a component. A later example in the same task addresses the harder case directly: where the integrity or provenance of acquired binaries cannot be confirmed, build the binaries from source after verifying that source's integrity and provenance. For most device manufacturers, negotiating source access from every supplier is not on the table, which leaves analyzing the binary you received.

The Finite State Platform, within the Finite State Product Security OS, reconciles source and binary findings into one view for this reason. It analyzes compiled firmware images and executables directly across ARM, ARM64, x86-64, MIPS, PowerPC, RISC-V, and smaller targets including ESP32, MSP430, and AVR, and it identifies firmware-only and closed-source components that no source scan will see.

What do EU CRA and FDA rules expect from code analysis?

Both regulations ask for written test evidence. The CRA wants regular security tests in the technical file. FDA wants static analysis reports with tool versions.

Every competing explainer treats SAST as a developer productivity choice. For anyone shipping a regulated connected product, it became a filing requirement.

EU Cyber Resilience Act. Regulation (EU) 2024/2847 applies from 11 December 2027. Annex I Part II obliges manufacturers to apply effective and regular tests and reviews of the security of the product. The word doing the work there is "regular." A single pre-launch scan does not satisfy a continuing obligation. Annex VII then requires the technical documentation to contain reports of the tests carried out to verify conformity, retained for 10 years after the product goes on the market or for the support period, whichever runs longer. Practical guidance on assembling that file sits on the EU CRA compliance page.

FDA premarket submissions. The current guidance, Cybersecurity in Medical Devices: Quality Management System Considerations and Content of Premarket Submissions, issued 3 February 2026, supersedes the June 2025 version. Under vulnerability testing it names static and dynamic code analysis, including testing for credentials that are hardcoded, default, easily guessed, or easily compromised. Two details in that section deserve attention:

  • The same list separately names software composition analysis of binary executable files. FDA asks for both the source-level analysis and the binary-level analysis.
  • A footnote states that for any testing tools used, the details provided may include the tool name, version information, and any settings or configuration options. A scan result with no record of which tool version and rule set produced it is weaker evidence.

The guidance also recommends security testing at regular intervals after release, commensurate with risk, and offers annually as an example.

Both regimes point the same direction. The scan is the easy part. Producing a dated, versioned, traceable record of every scan across every release and holding it for a decade is the part that needs a system.

What does shift-left security actually buy you with SAST?

Fixing a flaw during coding costs less than fixing it after release. NIST names this shifting left and ties it to reduced technical debt.

The SSDF states the principle directly in its introduction: in general, the earlier in the SDLC that security is addressed, the less effort and cost is ultimately required to achieve the same level of security. NIST adds that shifting left minimizes the technical debt of remediating early security flaws late in development or in production, and can produce software with stronger security and resiliency.

For connected devices the economics get sharper than for web software, and the reasons are physical:

  • A field update has a delivery cost. Pushing firmware to deployed devices means a release campaign, staged rollout, and a tail of devices that never update.
  • Some devices cannot be updated in the field. A flaw in that firmware is permanent for the life of the unit.
  • A post-authorization change may need a regulatory filing. For medical devices, changes that could affect cybersecurity may require a new premarket submission.
  • The support period is long. A CRA support period of several years means a vulnerability shipped today stays yours for years.

Shifting left has a limit worth naming. Earlier is cheaper for the code you own, and it does nothing for the supplier binary that arrives late in integration. Those need analysis at the point they enter the build, which is a different control at a different stage.

How do you run SAST in a CI/CD pipeline without stalling releases?

Run incremental scans on every pull request and a full scan nightly. Gate releases on new findings so the existing backlog stops blocking merges.

The pattern that survives contact with a shipping team:

  1. Baseline first, gate second. Run a full scan, triage it, and record the surviving findings as a known baseline. Gate only on findings introduced after that point.
  2. Split the cadence. Incremental scan on pull request for speed. Full-codebase scan nightly or weekly, where a longer run costs nobody's afternoon.
  3. Deliver findings where the code is. Into the pull request as review comments, not into a security dashboard a developer never opens. IDE plugins move this earlier still.
  4. Tune the rule set before blaming the tool. A default rule set aimed at web applications produces noise on embedded C. Disable what does not apply, write rules for the unsafe patterns specific to your platform, and re-baseline.
  5. Assign triage to a named person. SSDF PW.7.2 builds a human reviewer into the practice. An unreviewed queue becomes an ignored queue within two sprints.
  6. Record the run. Tool name, version, rule set version, configuration, date, and commit. FDA asks for it, the CRA technical file needs it, and reconstructing it retroactively is unpleasant.

On sequencing with other testing: SAST gates the merge, SCA runs at build and continuously afterward, DAST and fuzzing gate the release candidate, and penetration testing runs on a defined cadence against the artifact you are about to ship.

How do you choose a SAST tool for embedded code?

Start with language and toolchain support, then check buildable-source requirements, binary analysis ability, SARIF output, and measured false positive rates before pricing.

OWASP publishes selection criteria and puts one first as a prerequisite: the tool must support your programming language. For firmware that means real C and C++ coverage, and increasingly Rust. Several criteria on that list matter disproportionately for embedded work:

  • Requirement for buildable source code. Some engines need a successful compile. If your build only works inside a specific container with a vendor toolchain, establish this before signing anything.
  • Ability to run against binaries instead of source. OWASP lists this explicitly. It is the difference between covering three rows of the firmware table above and covering seven.
  • Framework and library comprehension. An engine that does not understand your RTOS abstractions will miss flows through them.
  • Accuracy, measured. False positive and false negative rates, and where available a score against the OWASP Benchmark project.
  • Output interoperability. SARIF, so findings consolidate.
  • CI/CD and IDE integration. Both, or developers will not see results in time to act on them.

On named tools, two cautions. OWASP marks FindBugs as legacy and unmaintained and directs users to SpotBugs with the FindSecBugs plugin for security rules. It also describes PMD as a code quality tool that does not focus on security issues. Any guide still recommending the first two as your open source starting point is out of date.

Current options worth evaluating, by category:

  • Open source: Semgrep, SpotBugs with FindSecBugs, Bandit for Python, Brakeman for Ruby, Flawfinder for C and C++, CodeQL via GitHub code scanning.
  • Commercial: Coverity Static Analysis (Black Duck), Fortify SAST (OpenText), Checkmarx, Veracode, Klocwork (Perforce), Polyspace (MathWorks) for C, C++, and Ada in safety-critical work.
  • Formal methods: Astrée (AbsInt), which uses abstract interpretation to prove the absence of certain runtime error classes rather than pattern-matching for them.

Vendor ownership in this market changed hands repeatedly over the past two years. Confirm current ownership and product naming against the vendor's own site before you cite either in a procurement document.

Finite State Team

Finite State Team

The Finite State team brings together experts in cybersecurity, embedded systems, and software supply chain risk to help connected device manufacturers secure their products and comply with evolving global regulations.

Ready to Level Up Your Security Knowledge?

Join thousands of security professionals learning from the best in the industry

Start Learning TodayStart Learning Today
Finite StateFinite State

Finite State is the Product Security Automation Platform that functions as an autonomous Product Security OS: design → verify → prove, grounded in what you ship.

Platform

Platform Overview
Ground Truth Inventory
Exploitability-Based Prioritization
Design-Time Architecture Security
Automated Evidence-Backed Compliance

Solutions

Device Manufacturers
Automotive
Medical Devices
Energy & Utilities
Government
Industrial

Resources

Blog
Resource Library
Webinars & Videos
Events
Documentation

Company

About Us
CareersHIRING
Press & News
Contact Sales
Media Inquiries
X

© 2026 Finite State. All rights reserved.

Privacy PolicyTerms of UseCustomer Terms and Conditions
Finite StateFinite State
Finite StateFinite State
Get a DemoGet a Demo