Safeguard 16.12 Code-level security checks

Safeguard 16.12 is an IG3 requirement to run static and dynamic analysis tools through the application life cycle. This page explains what an assessor tests, which evidence passes, what it costs and which parts are worth outsourcing.

On this page

What Safeguard 16.12 code-level security checks require and why they are hard to prove

If an assessor has asked you for proof of code-level checks, the requirement is Safeguard 16.12, which asks that static and dynamic analysis tools be applied within the application life cycle to verify that secure coding practices are followed. CIS places it in the Software asset class under the Protect security function, and it is an IG3 safeguard, so it applies to enterprises with security specialists and regulated, sensitive assets. The risk it addresses is familiar: insecure code reaches production because nobody checked it for the weaknesses that automated analysis can find, such as injection flaws, unsafe deserialization or hard-coded secrets. You own this control. CIS publishes the Safeguard and its assessment specification, but the scanning, the decisions about what gets scanned and the evidence are your responsibility.

The difficulty is that tool output alone does not prove coverage. A dashboard showing thousands of findings says nothing about how much of your in-house software was actually scanned. The CIS Controls Assessment Specification measures this through two metrics: Static Analysis Tool Coverage and Dynamic Analysis Tool Coverage, each expressed as the share of in-house developed software verified by the relevant tool type. To calculate either, you need an authoritative list of applications, which is why the specification names Safeguard 2.1, the software inventory, as a prerequisite. Ask yourself whether you can name every in-house application, show which ones run through a static pipeline and which through a dynamic test, and explain the gap for any that do not. If you cannot answer those questions from records, the assessor will treat the safeguard as unproven regardless of how capable the tools are.

Which applications, pipelines and teams fall inside the scope of 16.12

Safeguard 16.12 measures coverage as a share of in-house developed software, so the scope decision determines both the denominator and the work. The cards below separate the code you own from the code you host or buy, and tie each boundary to the inventory and tooling choices that make the measurement defensible.

In-house developed software

This is the only population the two 16.12 metrics count: the share of in-house developed software verified by a static analysis tool and the share verified by a dynamic analysis tool. Start by listing every application your teams write, including internal tools, scripts that ship to production, and customizations of open-source platforms. Each one needs a documented owner and a repository, or it cannot be shown as covered or uncovered.

Vendor-supplied code

Software a vendor delivers as a compiled product, appliance or SaaS service sits outside the 16.12 denominator because your organization did not develop it. Your obligations for that code shift to vendor assessment and to the third-party controls in Control 15 and Safeguards 16.4 and 16.5. Document each vendor product explicitly as excluded so an assessor can see the boundary was a decision, not an omission.

Hosted and acquired code

Code your team hosts but did not write, such as a managed open-source deployment you configure, or code acquired through a merger, needs a separate decision. Treat code you modify as in-house for the portion you changed, and record the acquired codebase as its own scope item with a date by which it will be measured. Mixed codebases are a common source of disputed coverage, so write the split rule down before the first scan.

Languages the tools support

Coverage counts only software a chosen tool can actually analyze. Semgrep Community Edition supports a wide list of languages, including C/C++, C#, Go, Java, JavaScript, TypeScript, Python, Ruby, Rust, PHP, Kotlin, Swift and Terraform. Any language outside your tool's support list is uncovered until a second tool or custom rule set handles it, so match the inventory of languages against the supported list before you set a coverage target.

Repositories and build pipelines

Scope the repositories that produce deployable code, then the pipelines that build and release them. A repository tool can run analysis on every merge request, but only if the pipeline is required to run it. Protected branches in GitLab Community Edition can block direct pushes and keep force pushes disabled, which helps keep unreviewed code from bypassing the scan stage. Confirm which branches and pipelines feed production before recording coverage.

Infrastructure-as-code and teams

Terraform and other infrastructure-as-code files define application infrastructure and carry security settings, so decide whether they count as in-house software for this Safeguard. Name the teams responsible for each repository, including platform engineers who write templates and product teams who consume them. Ownership gaps are where unscanned code usually sits, so each repository should map to one accountable team in the software inventory.

Software inventory as the prerequisite

The CAS lists Safeguard 2.1, establishing and maintaining a software inventory, as a prerequisite for measuring 16.12. Without an inventory, you cannot prove the denominator is complete, so an assessor will question any coverage figure. Reconcile repositories, build pipelines and deployed applications against the inventory each review cycle. The inventory is the document that turns a list of tools into a defensible scope.

How an assessor tests Safeguard 16.12 and which evidence they request

This table compares the assessor's test steps, the evidence requested and the findings that usually cause problems for Safeguard 16.12. Read each row as a question the assessor will ask and the artifact that answers it. CIS describes what to measure, not how, so confirm the assessor's sampling method and your own method in writing before fieldwork starts.

Test areaWhat the assessor checksEvidence requestedCommon finding
Software inventory prerequisite (2.1)Whether a current inventory of software exists that identifies which applications are in-house developed, so coverage can be calculatedSoftware inventory export with an owner, a development origin flag and a last-updated dateInventory omits internally built services or lists them without an origin, so the coverage denominator cannot be proven
Scope of in-house developed softwareWhether the population of in-house applications is defined, bounded and agreed with the organizationWritten scope statement, repository list, application register and any exclusions with approvalsScope silently excludes legacy or customer-facing applications, or includes third-party code that the organization does not build
Static Analysis Tool Coverage metricThe share of in-house developed software verified by a static analysis tool, measured against the scoped populationCoverage report from the analysis tool or pipeline showing which repositories were scanned, with dates and the tool versionCoverage is claimed from a tool configured on one application, or from a scan that was enabled once and not run since
Dynamic Analysis Tool Coverage metricThe share of in-house developed software verified by a dynamic analysis tool, such as testing a running applicationTest run logs, target lists and reports showing which running applications were exercised and whenDynamic testing covers only a staging demo, or results are not linked to the applications they describe
Pipeline and samplingWhether the assessor selects applications and pipelines across teams and languages, then traces each sample from code to scan resultPipeline definitions, sample scan records for each selected application and the reviewer's notes on gapsScans run on the main branch only, so feature branches and hotfixes reach production unscanned
Enforcement of secure coding checksWhether findings are triaged and whether high-risk results can block a merge or releaseBranch protection settings, quality gate configuration and records of blocked or waived findings with approvalsScans report but never block, and findings sit in a backlog with no owner or due date
Waivers and exceptionsWhether each suppressed or accepted finding has a documented reason, an approver and a review dateException register with rule identifiers, justification, approver and expiryRules are disabled broadly to reduce noise, with no record of who approved it
Confirmation of methodWhether the assessor's method and the organization's method are agreed before testingWritten test plan, agreed metric definitions and a list of tools and versions used to measure coverageMethod is discussed verbally only, so the metric is calculated differently at audit time than during preparation

How to roll out static and dynamic checks across the life cycle

This sequence moves Safeguard 16.12 from an inventory of in-house software to documented, measured analysis coverage, so each application has a known tool set, a gated pipeline and a coverage figure that an assessor can check against the Assessment Specification metrics.

  1. Inventory in-house applications and repositories

    Start from the software inventory that Safeguard 2.1 requires, because the Assessment Specification lists it as a prerequisite for measuring 16.12. Filter it to software your organization develops, including internal tools, customized packages and hosted applications built by your staff, and exclude commercial products you only configure. Record each application's owner, repositories, languages, frameworks and deployment targets. The output is a list of in-scope repositories mapped to applications, and the step is done when the development leads confirm that list is complete. This list is the denominator for the Static Analysis Tool Coverage and Dynamic Analysis Tool Coverage metrics, so an incomplete list inflates the percentage.

  2. Select static and dynamic tools per language and application type

    For each language and application type on the list, choose a static analysis tool that supports it and a dynamic testing approach suited to how the application is exposed, such as web applications, APIs or internal services. Semgrep Community Edition covers a broad set of languages with community or custom rules, but confirm current language support against the vendor's list before committing, and document any language it does not cover with a second tool. Record the selection, the rule sets enabled and the owner who approved each choice. The output is a tool matrix that names one or more tools for every repository, and the step closes when security and engineering leads sign it off.

  3. Wire static scans into build pipelines and merge gates

    Add static analysis as a stage in each repository's continuous integration pipeline so every change is scanned automatically, not only at release. Configure the scan to fail or flag the build for findings above an agreed severity, and make the result a required check before merge. In GitLab Community Edition, protected branches can restrict who may push or merge to main branches, block direct pushes and keep force pushes disabled, which stops changes from bypassing the scan. The output is a pipeline configuration per repository and a branch protection record. The step is done when a test change with a seeded finding is blocked from merging, and you keep that test result as evidence.

  4. Configure dynamic testing against staging environments

    Run dynamic analysis against a staging environment that mirrors production configuration but holds no live customer data, and keep it separate from production as Safeguard 16.8 requires. Give the scanner an authenticated session where the application uses login, so it reaches the functions that matter, and schedule scans on each release candidate as well as on a regular cadence. Confirm the environment is reachable from the scanner and that test accounts are scoped and logged. The output is a documented scan configuration and a first baseline report per application, and the step closes when that baseline has been reviewed by the application owner.

  5. Define triage, ownership and tracking of findings

    Set rules for how each static and dynamic finding is confirmed, assigned and closed. Decide who triages findings, how false positives are recorded with a reason, which severity needs a fix before release, and how items link to the vulnerability intake and severity rating processes covered by Safeguards 16.2 and 16.6. Track every finding in one system with an owner, a status and a date for each change of state. The output is a triage procedure and a findings register that can be sampled by an assessor, and the step is done when a sample of closed findings shows a fix, an accepted risk or a documented false positive for each.

  6. Measure coverage per application and report it

    Calculate the two metrics the Assessment Specification uses for Safeguard 16.12: the share of in-house developed software verified by a static analysis tool, and the share verified by a dynamic analysis tool. Compute them from the step 1 denominator, counting an application as covered only where its pipeline and dynamic scan actually run. Publish the figures per application and in total, keep the scan history that backs them, and review them on a set cadence with the owners. The output is a coverage report that names each application, its tools and its last scan, and the step is done when the report reconciles to the inventory with no unexplained gaps. Ask your assessor which evidence format they will accept for these measures before you finalize it.

Evidence that shows static and dynamic coverage over time

Safeguard 16.12 is scored as coverage, so an assessor needs to see which in-house software was scanned, with which tools and rules, and what happened to the findings. The cards below cover the artifacts that connect those answers, along with how to keep each one current between audits rather than assembling them at audit time.

In-scope application inventory

This is the denominator for both coverage metrics: the list of in-house developed applications and their repositories, pulled from the software inventory that Safeguard 2.1 requires. Each entry should name the owning team, the primary language and the pipeline that builds it. Review it on a fixed schedule and when new repositories are created, because an application missing from this list is invisible to the coverage calculation. Ask the assessor to confirm how acquired or hosted software is classified before the first review.

Scan configuration and rule sets in version control

Keep the Semgrep rule sets, CI job definitions and analyzer settings in the same repository system as the code they scan, with protected branches so changes to scanning rules need review. An assessor will ask who can weaken a rule and whether a change is traceable to an approved request. Record the rule set version used for each audit period so that results from different periods can be compared fairly.

CI pipeline logs for each merge or release

Pipeline logs show that the static analysis job ran on each merge or release, not only when someone remembered to run it. Confirm that failed or skipped scan jobs block the merge, and retain the logs for the full audit period. Gaps in the log series, such as a pipeline that was disabled for a sprint, are what an assessor will sample first, so schedule a monthly check that every in-scope repository produced scan results.

Dynamic scan reports tied to versioned builds

Dynamic analysis is only credible when each report names the build or release it tested, the target environment and the scan date. Store reports against the artifact version so that a finding can be traced to the code that produced it. Confirm that the dynamic testing environment is separated from production, and record any authenticated scan scope so the assessor can see which parts of the application were actually exercised.

Triage records with fix or accept decisions

Every finding needs a recorded outcome: fixed in a named commit, accepted with a documented reason and an approver, or marked as a false positive with the rule or evidence behind it. Accepted risks should carry an expiry date so they return to review. Assessors often judge the program by these records, because a high count of unreviewed findings suggests that scanning produces output nobody acts on.

Coverage calculations for each metric

Calculate Static Analysis Tool Coverage and Dynamic Analysis Tool Coverage as the share of in-house software verified by each tool type, and keep the worksheet with its source data. Schedule the calculation at a fixed interval, such as monthly, and store each result with the inventory snapshot it used. Note any application excluded from scope and the reason, because an unexplained exclusion lowers confidence in the reported percentage more than a low percentage does.

Which open-source tools produce the code and dependency evidence

Semgrep Community Edition is the tool that most directly produces static analysis evidence for Safeguard 16.12. It is licensed under LGPL-2.1-only and scans source code in a wide range of languages, including C/C++, C#, Go, Java, JavaScript, TypeScript, Python, Ruby, Rust, PHP, Kotlin, Swift and Terraform. Teams can run it with community rules, with custom rules that encode their own secure coding standards, or both, and it can run in CI/CD pipelines so that each change is scanned rather than only scanned before a release.

  • Language coverage: Confirm that every language your in-house software uses appears in the supported list, since the Static Analysis Tool Coverage metric depends on which code the tool actually verifies.
  • Custom rules: Encode your secure coding standard as rules so the scan checks the practices your organization defined, not only generic patterns.
  • Pipeline execution: Run the scan on every merge request or build so the output is a repeatable record linked to a specific commit.
  • Retained output: Store scan reports with the build identifier so an assessor can match findings to the code version that was tested.
  • License terms: LGPL-2.1-only permits use, but confirm with counsel how it applies to your distribution and modification model.

Check that the scan covers all in-house repositories in scope, and that the Semgrep rule set and version are recorded in the evidence.

What meeting Safeguard 16.12 costs in money and effort

This table breaks down the money and effort behind running static and dynamic analysis for Safeguard 16.12, who is paid for each part, whether it is one-time or recurring, and what pushes it up or down. Open-source tools remove license spend but not the engineering, triage and evidence work that the assessment specification measures. Use the drivers column to write a quote request that a partner or vendor can price against your own codebase.

Cost componentOne-time or recurringWhat drives itHow to keep it down
Tooling or licensesRecurring if commercial; none for the named open-source toolsCommercial analysis licenses scale with developers, repositories or scan volume. Community editions remove license spend but not operating effort.Confirm edition limits and features in writing before choosing. Budget operating effort for the open-source tools as carefully as for paid ones.
Engineering time to wire scans and tune rulesOne-time, with ongoing changesNumber of repositories, languages in use, CI/CD platform, and whether custom rules are needed for internal frameworks.Start with the languages that carry the most in-house code. Add repositories in waves and reuse one pipeline template.
Triage and false-positive managementRecurringScan noise, rule quality, and how findings are assigned, severity-rated and tracked to closure.Tune rules in a baseline run, suppress reviewed findings with recorded reasons, and tie triage to the Safeguard 16.2 and 16.6 processes.
Dynamic test environmentsOne-time build, recurring hosting and refreshNeed for a running, non-production copy of each application, test data, and authenticated scanning setup.Reuse existing non-production environments under Safeguard 16.8. Automate deployment so scans run against a fresh build.
Software inventory and coverage measurementRecurringAccuracy of the software inventory under Safeguard 2.1, since the assessment specification uses it as a prerequisite for measuring coverage.Generate the inventory from source control and build systems rather than maintaining a spreadsheet by hand.
Evidence upkeepRecurringHow often scan configurations, rule sets, run logs and coverage figures change, and how they are retained for assessors.Export scan results and pipeline configuration to a version-controlled, access-restricted store on each release.
External application testing or reviewRecurring or per engagementScope of applications, whether business logic is reviewed, and how much of the tool output a tester must validate. Covered by Safeguard 16.13.Scope the review to critical applications first. Ask for a written list of what the review covers and excludes.
Auditor samplingRecurring, per assessment cycleNumber of applications and releases the assessor selects, and whether scan records for each sampled release are complete.Keep one traceable record per release that links the commit, the scan run and the findings disposition.

What your team, an implementation partner and the auditor each own

Your organization owns the Safeguard. It is accountable for deciding which in-house software falls under the analysis requirement, for setting how findings are triaged, and for proving the checks keep running after any implementation work ends. Internal staff also hold the knowledge of the codebase that no outside party can replace, so they decide what counts as a false positive and what must be fixed before a release.

  • Software inventory: Maintain the list of in-house applications that the Safeguard measures, since Safeguard 2.1 is a prerequisite for measuring 16.12.
  • Risk decisions: Set the severity thresholds that block a merge or release, and record any accepted risk with an owner and an expiry date.
  • Triage authority: Name who may suppress a finding, who reviews suppressions and how those decisions are logged.
  • Operating evidence: Keep dated scan results, pipeline logs and coverage reports for the full period an assessor will sample.
  • Coverage tracking: Calculate the share of in-house software verified by static and dynamic analysis tools, the two metrics the assessment specification uses.

Before engaging any partner, confirm that someone internal can name every in-house application and state who signs off on accepted risk.

Where organizations fall short on code-level checks and how to close each gap

Most organizations that claim Safeguard 16.12 already run a scanner somewhere. The gaps appear when that scanner does not gate merges, measures the wrong code, or leaves no record that a finding was handled. Each card names one gap and the corrective step that closes it.

Scanners run but never block merges

A static analysis job that reports results without a required status check lets insecure code reach the main branch. Assessors reviewing 16.12 will ask whether the tool runs as a control or as an advisory report. Mark the scan job as a required check on protected branches, and make sure maintainers cannot bypass it. In GitLab, set push access to no one on protected branches so every change passes through the pipeline before merge.

Coverage measured on the wrong denominator

The CAS metrics measure the share of in-house developed software verified by analysis tools. Teams often divide scanned repositories by all repositories, which pulls in vendor code, forks and archived projects and makes coverage look lower or higher than it is. Start from the software inventory required by Safeguard 2.1, tag each application as in-house or third-party, and report coverage only against the in-house set. Record the exclusion rule in writing so the same denominator is used every period.

Dynamic testing skipped without staging

Dynamic analysis needs a running application, and many teams have no environment that resembles production. Without one, the dynamic coverage metric stays at zero for applications that only ever run locally. Confirm which in-house applications can run in a non-production environment that mirrors their configuration, and where one does not exist, scope the environment as a planned deliverable. Keep it separate from production, which also supports Safeguard 16.8.

Rule sets that drift without ownership

Teams often add custom rules, suppress noisy findings and pin different tool versions per repository. Over a few months, the same code can pass in one project and fail in another, and no one can explain why. Keep rule configuration in a single version-controlled repository, require review for every rule change or suppression, and record the tool and rule versions used in each pipeline. Semgrep Community Edition supports custom rules and CI/CD scanning, which makes this centralized configuration practical.

Findings without an owner or closure record

A scan that produces 200 findings and no triage decisions is not a working control. Assessors look for evidence that each finding was assigned, fixed, accepted with a documented reason, or marked as a false positive by a named person. Route findings into the defect tracker with an owner and a severity, and require a closure reason before an item can be closed. Review open findings on a fixed cadence and keep the history, not just the current count.

No proof that scans ran for a release

Teams often cannot show which scans ran against the code that shipped in a given release. Logs expire, pipelines are re-run and results are overwritten. Attach the scan outputs, tool versions and commit identifier to each release artifact or change record, and retain them for the period your audit requires. Confirm with your auditor which evidence format they accept before you design the retention process.

Common questions about cost, effort and outsourcing Safeguard 16.12

How much effort does Safeguard 16.12 take and what drives it?

The effort depends mainly on how much in-house software you develop, how many languages and repositories it spans, and how mature your pipelines already are. Safeguard 16.12 is scored by the share of in-house developed software verified by static analysis and the share verified by dynamic analysis, so the work grows with the size of that software estate. Teams with consistent build pipelines and a current software inventory usually have less to configure than teams with many unrelated repositories. No figure is given here because none is supplied; ask your assessor or implementation partner to break the effort into inventory, tool setup, rule tuning, triage and ongoing maintenance.

How long does implementation take for a typical scope?

Duration depends on scope, not on a fixed template, so no timeline is promised here. The main variables are the number of applications in scope, whether static and dynamic tools must be added to existing pipelines or new ones, and how many findings your teams must triage before coverage is meaningful. Because Safeguard 16.12 depends on Safeguard 2.1 (a software inventory), a missing inventory can extend the schedule. Ask for milestones tied to specific applications and repositories in a written, fixed-scope plan.

Can an in-house team implement code-level security checks without outside help?

Yes, many engineering organizations can do this themselves, particularly if they already run CI/CD pipelines and have security engineers who can write or tune rules. Outside help is most useful when the team lacks time, has many languages to cover, or needs an independent view of coverage for an assessment. Whichever route you choose, the organization remains responsible for its controls. An implementation partner can prepare systems and evidence, but only an independent auditor or assessor issues reports or certifications.

What does the work require from engineering and security staff?

Engineering staff must add scan steps to build pipelines, keep rules current with the languages they use, and act on findings inside their normal development workflow. Security staff must define which findings block a merge, review suppressions, and report coverage against the two Assessment Specification metrics. Both groups should agree on who owns triage so that findings do not accumulate without action. Expect this work to recur, because new repositories, dependencies and languages appear over time.

Are open-source tools sufficient for Safeguard 16.12?

Open-source tools can cover the technical activity of Safeguard 16.12, but sufficiency is a question about your environment and evidence needs, not a property of the tool alone. Semgrep Community Edition, for example, supports many common languages and can run in CI/CD pipelines with community or custom rules, while dynamic analysis requires separate tooling suited to your applications. Confirm language coverage, rule quality and reporting outputs against your own codebase before relying on them. Protected branches in GitLab Community Edition can also enforce that scanned code is the code that gets merged.

What should a fixed-scope quote for this safeguard include?

A useful quote lists the applications and repositories in scope, the languages and frameworks covered, the static and dynamic analysis tools to be deployed, and the pipelines that will change. It should name deliverables such as pipeline configuration, rule sets, a coverage report against the two metrics, runbooks and training for engineers. It should also state assumptions about the software inventory, client access, and who handles findings after handover. Ask for exclusions in writing, along with the support model if you want continuous tuning under a retainer.

What will an auditor check for this safeguard, and what will they not do?

An auditor will test whether the organization measures static and dynamic analysis coverage of in-house software and whether secure coding practices are verified in the life cycle. They will look for evidence such as pipeline configurations, scan results, coverage figures and records of how findings were handled. The auditor will not implement the tools, write your rules, or certify the safeguard on your behalf. Only an independent auditor, assessor or certification body issues reports or certificates, so confirm with them early which evidence they expect.

How DeployOpen scopes, implements and prepares evidence for Safeguard 16.12

DeployOpen plans, implements and documents static and dynamic analysis for in-house software inside your own infrastructure, so the tooling and records are yours. We prepare the systems and evidence for Safeguard 16.12, while your organization owns the control and an independent assessor reviews it.

How we scope

  • We confirm which in-house applications sit in scope and how each one is built, hosted and released.
  • We check that a current software inventory exists, since the CIS assessment specification lists Safeguard 2.1 as a prerequisite.
  • Engagements are fixed-scope, with scope and deliverables agreed in writing before any work starts.

How we build

  • We deploy static analysis, such as Semgrep Community Edition, into your CI/CD pipelines for the languages your teams use.
  • We set up dynamic analysis against test environments, separated from production, and define which findings block a release.
  • We configure GitLab protected branches so scanned code cannot reach main branches without the required checks passing.

How we hand over

  • We document the tool configuration, rule sets, pipeline gates and exception process so your team can run them.
  • We produce coverage records matching the two CIS metrics: static and dynamic analysis tool coverage of in-house software.
  • We hand over the evidence package, including pipeline logs, scan reports and approval records, for your auditor to review.

How we support

  • Ongoing support, upgrades and continuous testing are available as a retainer after handover.
  • We can keep rule sets current and re-verify coverage when new applications or languages enter the pipeline.
  • Confirm with us in the written scope exactly which tool versions, upgrades and coverage reports are included.

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.