Developer experience as a security control
This is not an argument for making security pleasant. It is the observation that every control has a bypass rate, that the bypass rate is set by how much effort the compliant path costs relative to the alternative, and that you can therefore change your actual security posture by changing effort rather than policy. A control nobody can comply with efficiently is a control that produces exceptions, and exceptions are where incidents come from.
What this does not replace
Enforcement. A pleasant developer experience with no gates is a set of suggestions, and teams under delivery pressure will decline suggestions in a predictable order starting with the ones that are hardest to justify skipping. Making the secure path easy raises compliance among people who want to comply; it does nothing about the case where compliance is genuinely inconvenient and nobody is checking.
It also does not replace judgement about which defaults are correct. A template that generates a service with authentication wired up encodes decisions somebody had to make properly, and if those decisions are wrong you have propagated them to forty services with excellent ergonomics.
So the honest framing is that experience work multiplies the value of a control that already exists and is enforced. Introduced instead of enforcement it produces a programme that looks modern and measures nothing.
Why does friction predict bypass rate?
Because the compliant path competes with the alternative on effort, at a moment when the developer is under time pressure and the security benefit is abstract. If requesting a credential through the approved route takes two days and pasting a long-lived key into a configuration file takes a minute, the key gets pasted, and no amount of training changes that arithmetic. The behaviour is rational given the costs presented, so the intervention that works is changing the costs.
This is measurable rather than theoretical. Count the exceptions each control generates and how long its compliant path takes. Controls with high exception rates almost always have a slow or unclear path, reliably enough that exception volume reads as a work queue for the platform team.
The corollary is that speeding up the compliant path is often a better security investment than adding a control. Reducing credential issuance from two days to two minutes removes the incentive behind your worst class of exposure, and needs nobody's cooperation to work.
| Friction point | What teams do instead | Cheaper design |
|---|---|---|
| Credential issuance takes days | Reuse an existing key, or paste a long-lived one into config | Self-service issuance of short-lived credentials, bound to workload identity |
| Pipeline security failure cannot be reproduced locally | Push repeatedly to CI until it passes, or ask for the check to be waived | The same check runnable with one command, same version, same rules |
| New service setup requires a security review to start | Build it inside an existing service where nobody will notice | Scaffolding that generates a compliant service, review only for deviations |
| Base image approval is a ticket | Use whatever image is on the internet and works | A small set of maintained images, current by default, pulled by digest |
| Exception requests go to a mailing list | Ship anyway and hope, or find the bypass flag | A pull request template that grants a time-limited, recorded exception |
| Findings arrive in a separate tool with a separate login | Never look at them | Findings appear as issues or comments in the tool they already use |
What belongs in a paved road?
Whatever a team would otherwise have to decide for themselves and usually decides once, badly, at the start of a project. Service scaffolding with authentication, logging, transport settings and a hardened container definition already present. A small set of maintained base images. A pipeline template that includes the security checks so nobody assembles their own. Standard patterns for retrieving secrets at runtime. Ownership metadata generated automatically rather than filled in on request.
The measure of a paved road is what proportion of production services are on it, and that number is worth tracking because it degrades quietly. A template updated in March does not update the twenty services generated from it in January, so without a mechanism to propagate changes you have a paved road that only covers new work. Propagation, through automated update pull requests or a base image rebuild, is what makes it an ongoing control rather than a starting gift.
Keep the road narrow. A platform offering three supported ways to do everything is a catalogue rather than a paved road, and it costs more to maintain than it saves. One good default with a documented escape hatch beats three options, and the hatch matters because teams with genuinely unusual requirements exist.
Why does local reproduction matter so much?
Because a check that can only be run in CI turns every fix into a push-and-wait cycle. A developer facing an unfamiliar security failure they cannot reproduce locally will iterate blindly against the pipeline, which is slow enough that after three attempts the reasonable move is to ask for a waiver. That is a bypass created purely by tooling design.
The requirement is specific: the same tool, same version, same rule set, one command, same output. Version skew is the usual failure, where the local run passes and CI fails because the rules moved, which destroys trust in the local check. Pin tool and rule versions in the repository so both paths read one definition.
The same applies to infrastructure policy. A developer who can evaluate a planned change against the current policy set before opening a pull request stops experiencing policy as arbitrary. One who cannot meets every rule as a surprise from a team they do not talk to.
How do you make the finding itself useful?
Deliver it where the work already happens, and make it specific enough to act on without investigation. A finding as a comment on the changed line, naming the rule, the file, the introduced version and the fixed version, is a few minutes of work. The same finding as a row in a dashboard behind a separate login is an afternoon, and an afternoon of unplanned work is what gets deferred.
Suppress the noise aggressively at the source rather than expecting readers to filter it. Findings on code the change did not touch, duplicates of the same dependency issue reported by two tools, and findings with no available fix should not appear in a review. Each one that does reduces the attention paid to the ones that matter, and attention is the resource you are actually managing.
Give every finding a next action. Patch to this version. Remove this permission. Add this field to the manifest. Where the next action is genuinely a judgement call, that finding belongs with security first, not with the developer, because sending an ambiguous item to someone with no context is how backlogs become permanent.
What can you measure and test this week?
Time three things: how long it takes a new engineer to create a compliant service, how long it takes to obtain a credential for a new integration, and how long from a security finding appearing to a fix being merged for a simple dependency bump. Those three numbers describe your real security posture more accurately than a tool inventory does, because they predict what happens under pressure.
Then count exceptions by control and put that list next to the time each compliant path takes. The two columns usually explain each other, and the control at the top is your next piece of platform work rather than your next training session.
The test that most often reveals a problem: ask a developer who did not build the pipeline to reproduce, on their own machine, the last security failure their team hit in CI. If they cannot do it in ten minutes, you have found the mechanism generating your waivers.
Common questions
- Why is developer experience a security concern?
- Because every control has a bypass rate, and that rate is set by how much effort the compliant path costs compared with the alternative at the moment someone is under delivery pressure. If obtaining a credential properly takes two days and pasting a long-lived key takes a minute, the key gets pasted. Reducing the cost of the compliant path changes behaviour in a way that training does not.
- Does good tooling remove the need for security gates?
- No. Without enforcement, a well-designed path is a set of suggestions, and teams under pressure decline suggestions. Making the secure route easy raises compliance among people who already want to comply, and does nothing where compliance is inconvenient and unchecked. Experience work multiplies the value of a control that exists and is enforced; used as a substitute for enforcement it measures nothing.
- What is a paved road in DevSecOps?
- A supported default path that already contains the decisions a team would otherwise make once, badly, at project start: service scaffolding with authentication and logging wired up, a hardened container definition, a small set of maintained base images, a pipeline template containing the security checks, and a standard way to fetch secrets at runtime. Keep it narrow, one good default with a documented escape hatch, rather than a catalogue of options.
- Why should security checks be runnable locally?
- Because a check that only runs in CI turns every fix into a push-and-wait cycle, and after three failed attempts asking for a waiver becomes the reasonable move. The requirement is the same tool, same version and same rule set, invoked with one command. Pin tool and rule versions in the repository, otherwise version skew makes local runs pass while CI fails and nobody trusts the local check again.
- How should a security finding be presented to a developer?
- In the tool they already use, as a comment on the changed line, naming the rule, the file, the current version and the fixed version, with a concrete next action. That turns it into minutes of work. A row in a separate dashboard behind another login turns it into an afternoon of unplanned investigation, which is what gets deferred indefinitely. Findings that are genuinely a judgement call should go to security first.
- How do you measure whether friction is hurting security?
- Count exceptions and waivers per control, and put that list beside how long each compliant path takes to complete. The two columns usually explain each other, and the control at the top is your next piece of platform work. Also time three things: creating a compliant new service, obtaining a credential for a new integration, and merging a fix for a simple dependency finding.