
A security team and a development team walk into a sprint planning meeting. The security team wants a vulnerability scan to block the build. The development team points out that the scan adds twenty minutes to a pipeline that was previously six minutes. The security team says that’s the cost of compliance. The development team says they have a release tomorrow and the gate will block it. The security team says that’s also the cost of compliance. The director of engineering looks at the calendar. This is roughly the dynamic in every organization I’ve worked with that takes security seriously and ships software regularly. The friction is real. It comes from the fact that the security team and the development team have different incentives, different time horizons, and different definitions of “done.” The good news is that the friction is solvable. Most of it. Not all of it; some of the friction is a healthy negotiation that should keep happening. But the version where the security team is universally seen as the people who slow everything down, and the development team is universally seen as the people who don’t take security seriously, is a failure mode, and most of the time it’s preventable. This article is a working engineer’s take on what makes the security/CI dynamic dysfunctional, what makes it functional, and how to push from the first toward the second without either side having to abandon their actual responsibilities. What the security team actually wants The security team is graded on something that’s hard to define and harder to measure. They’re supposed to prevent incidents. The metric for that is “incidents that didn’t happen,” which is, by construction, not directly observable. They’re supposed to satisfy compliance requirements. The compliance requirements are written in specific language that may or may not match the engineering reality. They’re supposed to maintain the security posture. The posture is the cumulative effect of decisions made by other teams. What this means in practice: the security team is risk-averse. They’re risk-averse because they’re held accountable for risks that materialize and they’re not given credit for risks that are prevented. The asymmetric incentive pushes them toward “block more, audit more, scan more.” If you’re on the development side and you find this annoying, the security team finds it annoying too. They didn’t choose the incentive structure. They’re operating in it. What the security team wants, in my experience, is to be in the room at the start — not the end. The audit that happens after the architecture is decided, after the data model is committed, after the API contracts are written, is the most expensive version of security work. By that point, the findings aren't suggestions; they're rework. What the security team wants is to be part of the design conversation, where the cost of getting it right is low and the cost of getting it wrong hasn't compounded yet. The protocols they're asking for are easier to build in than to retrofit. The teams that involve security at inception spend less time in remediation than the teams that involve security at release. Most security engineers know this from experience. Most of them have also learned that saying it doesn't change much — the invitation to the inception meeting must come from the other side. What the development team wants The development team has a roadmap. The roadmap has commitments. The commitments are tied to compensation, performance reviews, and the team’s relationship with the broader organization. They’re not opposed to security; they’re working in a system where the visible thing they produce is the thing they ship, and security work is mostly invisible. The development team also doesn’t want to introduce vulnerabilities. The frame “developers don’t care about security” is wrong. Developers care about not being the source of an incident. They care about not being the engineer who shipped the bug that was on the front page of TechCrunch. The motivation is there. What’s missing, in the dysfunctional version of the dynamic, is the alignment between the security work and the work the developers can actually do during a sprint. If security is something that happens to you, in the form of a scan that runs, produces findings, and assigns them back, the developer’s experience is reactive. Reactive work is harder to plan around than proactive work. Reactive work creates resentment. Where the friction comes from The specific friction points I’ve watched repeat across organizations: Scan latency. A scan that takes twenty minutes is sometimes acceptable; a scan that takes ninety minutes is intolerable in a CI pipeline that the team expects to complete in fifteen. Latency directly drives developer behavior. Slow scans get bypassed; bypassed scans don’t catch findings. False positive rate. A scan that produces 200 findings, of which 195 are noise, trains the team to ignore the output. By the time the five real findings show up, nobody is reading the report. Findings without context. A finding that says “potential vulnerability in line 142” without explaining what the vulnerability is, why it matters, or how to fix it puts the burden on the developer to translate from scanner output to action. Most developers don’t have the security background to do this efficiently. Most security teams don’t write the context into the finding because they’re too busy. Gate behavior that’s binary. A gate that says “pass or fail” doesn’t capture nuance. A medium-severity finding in test code shouldn’t block the same way a high-severity finding in production code should. The teams that gate uniformly produce blocks that don’t match the actual risk; the teams that gate too leniently let real things through. Late-stage findings. A finding that appears in a release-branch scan, three days before launch, is much more expensive to act on than the same finding in a feature-branch scan two weeks earlier. The teams that scan late produce findings that arrive when the team can’t easily address them. Process differences. The security team’s tooling, processes, and tracking are often separate from the development team’s tooling, processes, and tracking. Cross-system handoffs lose context. The friction point that caused the most damage in practice was a deployment window constraint nobody had written down clearly. The security team requires a minimum 48-hour review window before any deployment. In practice, that meant nothing could go out from Thursday onward. A change merged Thursday morning couldn't be deployed until Monday at the earliest, accounting for the weekend. For a team shipping weekly, that window quietly ate a quarter of the deployable calendar. The constraint wasn't unreasonable in isolation; the security team needed time to review and rushing that review was how things got missed. The problem was that the constraint wasn't visible in the pipeline. It wasn't a gate that failed with a message. It was an informal rule that new team members didn't know about, that wasn't enforced consistently, and that surfaced as a surprise when someone tried to deploy on a Thursday afternoon before a release. The fix was making the constraint explicit — a pipeline check that flagged deployments attempted inside the review window, with a message explaining why and who to contact for an exception. The rule didn't change. Making it visible reduced the friction significantly. What functional looks like The teams I’ve seen do this well share characteristics. Each one is doing the obvious things, but in combination they produce a different feel. Scans run on the developer’s branch, not the release branch. The first scan is on the PR. The PR comment is the feedback. The developer fixes the finding before merging. By the time code reaches the release branch, the issues that scanners catch have already been resolved. Scan time is engineered to fit the CI budget. If the scan adds more than five minutes to the PR pipeline, the team invests in incremental scanning, parallelization, or scope reduction. The investment is treated as part of the security program, not a luxury. False positive triage is a continuous process, not an event. Custom suppression rules are added as soon as a class of false positive is identified. The signal-to-noise ratio is monitored as a leading indicator. A scan that’s drifting toward noise gets attention before the team disengages. Findings include actionable context. Every finding posted to a PR includes the rule explanation, severity rationale, and a suggested fix where possible. The developer doesn’t have to translate from scanner output to action; the action is in the comment. Gates are graduated, not binary. Critical and high-severity findings on production code paths block. Medium and low don’t. Findings on test code or sample code don’t block. The graduation captures the actual operational risk rather than treating all findings as equal. Security team and development team share tooling for tracking. Findings live in the same ticket system as feature work. The security team’s view and the development team’s view are different filters on the same data. Handoffs don’t lose context because there’s no handoff. Security engineers are embedded in feature work. Not on every team, but enough that there’s regular exposure. Code reviews include security perspective for non-trivial changes. Design reviews include security input at the design stage, not at the audit stage. The single change that produced the biggest improvement was moving scans from the release branch to every commit and every PR. Before the change, the first scan a developer saw was the one that ran against the release candidate — days or weeks after the code was written, when the context was gone and the fix was expensive. After the change, the scan ran on every PR and posted results as a comment before the review. The developer who introduced the finding was still in the code, still knew what they were trying to do, and could fix it in the same sitting. The findings didn't disappear — the same classes of issues kept appearing — but the cost per finding dropped significantly. A finding caught at PR stage takes minutes to fix. The same finding caught at release stage takes a meeting, a ticket, a branch, and a re-deploy. The volume of findings reaching the release branch dropped within the first month. The security team spent less time in release-gate reviews because there was less to review. The development team stopped experiencing security as something that happened to them at the worst possible moment. That one structural change — scan earlier, feedback earlier educated more than any process conversation had. The conversations that matter The conversations that move a team from dysfunctional to functional aren’t about the tools. They’re about the framing of the work. The security team has to be willing to say what’s blocking-worthy and what isn’t. Not every finding is a release blocker. The team that gates everything ends up with engineering that bypasses the gate. The team that’s selective about gates produces gates that engineering respects. The development team has to be willing to take security work seriously even when the immediate cost is higher than the immediate benefit. A finding that the team has to fix this sprint, instead of the feature they wanted to fix, is a real cost. The team that always defers security to “next sprint” produces a backlog that grows; the team that absorbs the cost as part of normal work has fewer crises later. The leadership has to back both. A security team that gets overruled every time they push back becomes powerless and stops pushing back. A development team that can’t ship anything because security blocks every release becomes resentful and starts looking for workarounds. The leadership’s job is to back the security team’s authority while also holding them accountable for not blocking work that doesn’t actually need blocking. The version of the conversation I’ve heard work best is something like: “We’re going to gate on critical and high findings, in production code paths, that are externally reachable. We’re not going to gate on medium and low. We’re going to track those, but they’re not blocking. The security team and the development team agree on this; we revisit quarterly.” That conversation, and its variants, is what produces a functional pipeline. The conversation that shifted the dynamic most was a quarterly review we'd committed to when we set up the gate. The initial policy was straightforward: block on critical and high, track medium and low. The first quarter's data told a more complicated story. A significant portion of the high-severity blocks were on dependencies flagged by the scanner that had no exploitable path in our codebase — the vulnerable function existed in the library, but we never called it. The security team knew this. The development team knew this. Neither had a process to act on it. The quarterly review was where that changed. We added reachability as a factor in the gate decision — a high-severity finding in an unreachable code path moved from blocking to tracked. The security team didn't lose visibility; the finding still appeared in the dashboard. The development team stopped hitting blocks that everyone agreed weren't real risks. Release frequency improved. More importantly, the development team started taking the remaining blocks seriously, because the remaining blocks were the ones that mattered. The quarterly cadence kept the policy from calcifying. The second review produced another refinement. The third produced a smaller one. The policy got more accurate over time because we kept looking at the data. What I’d build into a new pipeline If I were standing up a new CI/CD pipeline with security integration: Run SAST on every PR, against the diff, with results posted as PR comments. Latency target: under five minutes. Run dependency scanning on every PR. Block on critical CVEs. Track high and below. Run DAST against a staging environment, on a separate cadence (not blocking PRs). Triage findings into the same tracking system. Generate SBOM on every release artifact. Validate against a CVE database. Alert on new CVEs that affect deployed versions. Configure the gate to block on: any new critical or high SAST finding in production code, any new critical CVE in dependencies, any new secret detected in code. Don’t gate on medium SAST findings, on low CVEs, or on test-code findings. Provide a risk acceptance path with engineering manager + security lead sign-off, expiration date, and re-review. Make it usable; if it’s painful to invoke, people will avoid the gate altogether. Track the friction. Measure how often the gate produces a “real” block (a finding that should have been caught) vs. a “false” block (a finding that gets risk-accepted). If the false-block rate is high, tune. Treat the pipeline as a product, with the security team and development team both as customers. The pipeline serves both. Friction in the pipeline is a bug, not a feature. The pipeline change I'd point to first is also the simplest one: we made the security team's 48-hour review window visible in the pipeline itself. Before the change, the constraint existed as an informal rule — known to some, unknown to others, enforced inconsistently, and experienced as a surprise by anyone who tried to deploy on a Thursday afternoon. After the change, the pipeline checked the deployment window and failed with a specific message: this deployment falls within the security review window, here's the earliest it can proceed, here's who to contact for an exception. The rule didn't change. The security team's requirements didn't change. What changed was that the constraint was now part of the system rather than part of tribal knowledge. New team members hit the gate, read the message, and understood the process. Exception requests went to the right person. The security team stopped being surprised by deployments they hadn't reviewed. The development team stopped feeling like the constraint was arbitrary. The friction that remained was the friction the constraint was supposed to create — and that's the right outcome. Making implicit constraints explicit in the pipeline is the cheapest, highest-return security investment most teams haven't made. What this is actually about The friction between security and development isn’t an accident of personalities. It’s the natural result of two functions that are graded on different things, working on the same codebase. The friction won’t go away by anyone trying harder. The friction reduces when the system is designed to align the incentives. When the security team gets credit for findings that didn’t ship, not just for findings they reported. When the development team gets credit for fixing security issues, not just for shipping features. When the leadership measures both as components of the same outcome. The hostile version of this dynamic — security team is “blockers,” development team is “irresponsible” — is a sign that the system is failing both groups. Each group is doing what their incentives reward. The result is dysfunctional because the incentives are misaligned. The way to fix the dynamic is mostly not to talk to the people. It’s to fix the incentives. Track the right things. Reward the right things. Make security work visible. Make development friction visible. Look at the data. Adjust. Most teams don’t get to a perfect equilibrium. The good ones get to a working one. The working version has tension — security and development are still negotiating, still pushing back on each other — but the tension produces better software. The dysfunctional version has tension that produces resentment, workarounds, and worse software. The lever that changed the dynamic more than anything else wasn't a process change or a tool change — it was proof of concept. The argument that security work slows development down is hard to counter with assertions. It's easy to counter with data. A test-driven development approach, applied to security requirements the same way it's applied to functional requirements, produced a measurable reduction in development time — not despite the security work, but partly because of it. Writing the security test first meant the requirement was explicit before the code existed. The finding that would have appeared in a scan three weeks later appeared as a failing test on day one. The fix happened before the pattern spread to five other places in the codebase. The POC was enough to shift the conversation from "security slows us down" to "the way we were doing security slowed us down." That distinction is the one worth fighting for. Security integrated at the start of the development cycle, expressed as tests that run in the same pipeline as everything else, doesn't add time. It moves the cost to where the cost is lowest. The security team doesn’t actually hate the CI/CD pipeline. They hate the version of the pipeline that punishes them for doing their job. Build a pipeline that lets them do their job without punishing the development team for doing theirs, and the friction drops to a manageable level. That’s not a slogan. It’s a daily set of small decisions about how the pipeline is configured, how findings are presented, how gates are calibrated, and how the work is shared. Most teams that get this right get there gradually, with a lot of iteration. The ones that try to solve it with a single big change usually fail. The patient, iterative version is the one that works. \
View original source — Hacker Noon ↗


