Black Shard

Insights24 April 2026

Shifting Security Left Without Slowing Delivery Down

Security gates fail when developers stop believing them. A field note on secret scanning, dependency checks and IaC gates that block only what matters.

Dark factory assembly line with one station lit by a cyan inspection lamp

Noise, not tooling, is why shift-left fails

Most teams that set out to shift security left already own the right tools. They fail anyway, and the failure looks the same everywhere: a scanner gets wired into CI, it fires on a few hundred findings in the first week, most of them irrelevant to the change at hand, and within a month developers treat the security stage the way they treat a flaky test. They rerun it, they override it, or they quietly route around it. A gate that cries wolf gets deleted, formally or otherwise.

The version that survives is built on one rule that is stricter than it sounds: nothing goes on the blocking path unless it has a near-zero false positive rate and a fix the developer can apply in minutes. Everything else runs in report-only mode and feeds a backlog that a named person owns. That single rule sorts the entire tooling landscape. Secret scanning earns a blocking slot almost immediately. Dependency scanning earns it only after aggressive filtering. Infrastructure-as-code and static analysis earn it for a small curated subset of rules, and no more.

Secret scanning is the one gate that should never be soft

Secrets are the place to start because the findings are binary. A live credential in a commit is not a matter of judgement or exploitability analysis; it is wrong every single time, and the fix is always the same. Run detection at two points: a pre-commit hook on the developer's machine, scanning only the staged diff so it returns in well under a second, and server-side push protection as the backstop. Both are necessary. Hooks are opt-in per clone and trivially skipped with a flag, so the server-side check is the actual control; the local hook exists to catch the mistake at the cheapest possible moment, before it enters history.

Precision comes from choosing detectors carefully. Structured tokens with known prefixes and check digits (cloud provider keys, platform tokens, signed connection strings) can block with essentially no false positives. Generic entropy rules are where the noise lives; run those report-only until you have tuned them against your own repositories. Grandfather existing test fixtures and documented examples through a baseline file, and require an inline allowlist comment with a stated reason for any new exception, so the exemption itself is reviewable in the same diff.

The failure message matters as much as the detection. A secret that has touched a remote once is compromised: rewriting history does not recall it from clones, CI caches, forks or the platform's event stream. The only correct response is to revoke and rotate the credential, and the gate should say exactly that when it fires, with a link to the rotation runbook. Gates that tell the developer precisely what to do next keep their credibility. Gates that print a rule ID and exit 1 lose it.

Dependency checks: block what is reachable and fixable

The naive configuration fails any build with a known high or critical vulnerability anywhere in the tree. On a typical Node or Python project that surfaces dozens of findings on day one, most of them in transitive development dependencies, several with no released fix. Developers learn within a fortnight that the gate has no relationship to real risk, and from then on every override is rubber-stamped.

The blocking rule that holds up is narrower: severity at high or critical, in a dependency that ships to production rather than one confined to the build toolchain, and a fixed version actually released. If no fix exists, blocking the build achieves nothing except teaching people that overrides are normal; those findings belong in the visibility lane with an owner and a weekly look. Commit lockfiles and make CI install from them, otherwise scan results are not reproducible and the gate will fire on changes nobody made.

Two additions make the gate feel like help rather than obstruction. First, automated upgrade pull requests (Renovate or Dependabot, grouped and scheduled) so the pipeline is not just saying no, it is handing over the yes; the gate stops new vulnerable versions arriving while the bot drains the existing pool. Second, a scheduled scan of the default branch, because new advisories are published against versions you shipped months ago, and a scan that only runs at pull request time will never see them.

IaC scanning: scan the plan, curate the policy set

Infrastructure-as-code scanners ship with hundreds of rules, and enabling all of them as blocking is how you end up with engineers arguing about tagging standards inside a security gate. The blocking set should be short and boring: the misconfigurations that actually cause incidents.

Scan the rendered plan, not just the source. Terraform's plan output in JSON, a compiled Bicep template or an ARM what-if result shows what will actually be deployed after modules and variables resolve; raw source scanning misses the values a module injects and flags placeholders a variable was always going to replace. On Azure estates the serious findings cluster tightly: public network access left enabled on storage accounts and Key Vault, connection strings sitting where a managed identity should be, and role assignments made at subscription scope out of convenience. A short policy set aimed at that cluster catches most of the real risk at a fraction of the noise. Everything else runs report-only and gets reviewed on a cadence, not at merge time.

  • Storage reachable from the public internet
  • Network rules open to the whole internet on management ports such as SSH and RDP
  • Wildcard or subscription-scope role assignments where a resource-scope grant would do
  • Encryption or minimum TLS settings disabled where the platform supports them by default
  • Credentials passed as plain-text variables instead of a vault reference or managed identity

Baseline the past, block only the new

The mechanism that makes all of this survivable on an existing codebase is the ratchet. On day one, snapshot every current finding into a baseline and exempt it; the gate blocks only what a change introduces. Developers accept responsibility for their own diff without complaint. They revolt, correctly, when an unrelated pull request is held hostage by five years of accumulated debt. The baseline is a debt register, not an amnesty: it needs an owner, a burn-down cadence and visibility in whatever forum reviews engineering health, but it lives on the reporting lane, not the blocking one.

Then hold the gates to a budget. Pre-commit work should finish in about a second, which means scanning staged diffs only. The blocking CI stage should add low single-digit minutes and run in parallel with tests; anything slower moves to an asynchronous job. Watch the override rate as a first-class metric: if a gate is overridden more than occasionally, either the rule is wrong or the fix is too hard to reach, and both of those are the gate owner's problem to solve, not the developer's to endure.

Sequence the rollout, and run each gate like a product

Order matters because each gate has to prove value before the next one lands. Secret scanning goes first: highest precision, cheapest fix, and a rotation runbook to accompany it. The dependency gate follows once the reachable-and-fixable filter and the upgrade automation are in place. IaC scanning comes third, blocking on the curated set against rendered plans. Full static analysis goes last and stays report-only until it has been tuned against your codebase for a while; it is the noisiest class of tool and the fastest way to squander the credibility the earlier gates earned.

Treat every gate as a product with three service levels: false positive rate on the blocking path, seconds added to the pipeline, and override rate. When we build delivery pipelines into client software, those three numbers are the review agenda; the specific scanners matter far less than whether developers still believe the red light means something. A pipeline that blocks rarely and is right every time does more for security culture than any policy document, because it turns the gate from an obstacle into a colleague with good judgement.

Ship software you can defend.

Australia-wide, from our Brisbane head office. Someone will contact you as soon as possible.

Open a briefinfo@blackshard.com.au