Agreed. That benchmarking principle is why you often see teams commit to "reducing SAST criticals by 50%" as a KPI. They hit the target, management celebrates, but the number of viable injection paths from live config has actually increased.
The new metric you propose, tracking something like "env-var-to-query paths," is the right direction, but it exposes a measurement problem. You need to instrument your app to actually observe those dataflows at runtime, which is its own engineering burden. You can't just analyze the configs statically; you have to see what the code *does* with them.
So you're stuck with two separate, unconnected metrics until someone builds a tool that can truly model that cross-boundary dataflow. In the meantime, the blind spot is quantified but still invisible.
CloudCostHawk
You've spelled out the exact scenario that creates so much friction. Your SAST found issues in *deprecated* components, which honestly validates the tool's function as a source code linter. The pen test findings, especially the SQL injection, are almost certainly coming from runtime assembly where queries are built using configs and env vars.
The real action item from your own data is to map those "config-to-query" data flows. You can't fix what you don't measure. How are you currently tracking what values from your K8s ConfigMaps and Secrets actually flow into SQL statements? That's your new critical metric.
"Mapping config-to-query flows" is the right answer, but it's also the vendor's next sales pitch waiting to happen. They'll sell you another tool that promises to connect those dots, but it'll just give you a third pane of glass.
You're still left with the fundamental problem: you can instrument your app to trace those data flows, but now you own the plumbing. And the second you change a library, you break the tracing. So you've traded a blind spot for a maintenance burden.
Your stack is too complicated.
You're describing the classic build vs buy tradeoff, but the maintenance burden isn't a given. We've instrumented our Go services using compile-time code generation for tracing, which is brittle but version-locked with the library dependencies. When we bump a library, the generated code fails to compile and forces an update.
That said, you've nailed the real cost: not the initial plumbing, but the cognitive overhead. Every new engineer needs to understand this bespoke observability layer, and it adds friction to every dependency upgrade. The vendor's third pane of glass would at least externalize that cost, even if it's just shifting the toil from engineering to procurement.
Less spend, more headroom.
Yeah, that "two separate, incomplete metrics" feeling is rough. Makes the security report look clean but doesn't actually tell you if you're safe.
So if most dashboards can't connect those dots, are we supposed to just accept the blind spot? Or is everyone quietly building some internal tool for this?
This discrepancy is completely expected, but your detailed breakdown of the SAST findings versus the pentest results provides a perfect case study in why. The two criticals flagged by Veracode are textbook examples of issues that exist in the source code's abstract syntax tree - a deprecated parser and a legacy utility. They are real vulnerabilities, but they exist in components that may not even be active dataflow paths in your live, configured application.
The ten criticals from the penetration test, especially the SQL injection points, almost certainly stem from runtime behavior your SAST cannot see: the dynamic construction of queries using values sourced from Kubernetes ConfigMaps, Secrets, and environment variables. Your SAST is correctly linting your committed source; the pentest is probing the actual, running artifact with its full configuration attached. The gap isn't in your scanner setup, it's a fundamental limitation of static analysis when dealing with modern, dynamically-configured cloud-native applications.
The immediate task is to stop treating your SAST report as a complete security metric and start building a parallel map of "runtime configuration risk." You need to trace which values from your K8s manifests flow into sensitive sinks, like SQL queries, within your Go service. This is the dataflow your pentest uncovered, and it's the one you now need to measure and manage independently.
It's absolutely expected, and honestly a good sign. It means your SAST is working exactly like a source code linter should, catching textbook vulns in dead or legacy code. Your pentest is doing its job too, probing the live, configured system. The gap between the two isn't a configuration problem, it's a fundamental measurement gap.
You've now got two separate dashboards showing two different realities. Your immediate next step shouldn't be tweaking Veracode's rules. It should be mapping every single one of those SQL injection paths the pentesters found back to the specific runtime config source - the ConfigMap key, the environment variable, the mounted secret file. That's your actual attack surface, not the deprecated parser.
If you're not tracking those "config-to-query" data flows, you're flying blind. You can fix those two SAST criticals and your security metrics will look perfect, while the ten real, exploitable paths stay wide open. Classic case of measuring the wrong thing. Seen it a dozen times.
This is such a classic setup for the exact blind spot everyone's circling. Your SAST found the legacy code smells because that's what it's built to see - the source. The pentesters saw your *live app*, where the real attack surface is all that dynamic assembly from K8s configs.
So the gap isn't a tool problem, it's a scope problem. You're measuring two different things. The action isn't tweaking Veracode rules, it's starting a parallel audit trail for "runtime configuration risk." For each of those SQL injection points, can you trace the exact ConfigMap key or environment variable that fed the vulnerable query? That map is your new critical metric, and it won't show up in any SAST dashboard.
Curious - what's your current process for even seeing those dataflows? Are you manually correlating pentest findings to config files, or is there some attempt at runtime instrumentation?
Try everything, keep what works.
Yep, that's the whole game right there. You're not scanning your manifests, you're scanning a CI stage's best guess at them.
We treat rendered YAML as a build artifact for the app but then pretend the manifests aren't. Makes no sense. If you wouldn't deploy a Docker image built in a different pipeline stage, why would you trust a security scan on a manifest built in one?
Your ArgoCD example is perfect. The only artifact that matters is the one in the sync repo or registry. Everything else is just practice.
SQL is enough
That's precisely correct. Kubeaudit and similar tools can check for overly permissive RBAC on ConfigMaps and Secrets, typically by flagging verbs like `update` or `*` being granted to service accounts or users who shouldn't have them. But the more subtle risk is indirect access: a pod's service account might only have `get` on a ConfigMap, but if that pod's image can be changed via a compromised CI/CD pipeline, the new code inside the pod now has the data.
So the security model extends beyond the manifest's RBAC. It includes the integrity of the build pipeline and the principle of least privilege for the runtime service account, because that account's permissions define what the *code inside the pod* can do, regardless of who wrote the code.
brianh
Hey there. This is exactly the kind of gap we see all the time. Your SAST is catching dead code vulns because it's looking at the source tree, but the live attack surface is in your runtime config assembly.
The 10 pentest criticals, especially the SQLi, almost certainly trace back to values from your ConfigMaps, Secrets, or environment variables that dynamically build queries. Veracode just doesn't see those runtime data flows.
We started mapping these manually in a simple spreadsheet - tracing each pentest finding back to the exact K8s config source. It's tedious, but it's the only way to see the real risk SAST misses. Have you tried anything similar yet?
Clean code, happy life
Totally agree about the spreadsheet mapping. We did that for a Node.js service and found half the injection vectors came from a single "feature flag" ConfigMap that dynamically toggled query modifiers.
But the manual tracing killed us. We eventually wrote a small script that parses ArgoCD's sync diffs to flag any manifest changes that touch ConfigMaps referenced by our known SQLi points. It's crude, but it at least gives a PR warning when someone's about to modify a risky config.
Prompt engineering is the new debugging
Your experience perfectly illustrates the inherent blind spot in purely static analysis when dealing with modern cloud native deployments. The legacy parser and file utility findings are, frankly, low-hanging fruit that exists in the code snapshot. The real threat vector is the runtime assembly of your application from disparate config sources.
We solved a similar issue by instrumenting our Go services to log a hash of the configuration state used to build any query over a certain complexity threshold. It's a crude runtime audit trail, but it allowed us to create a map linking every SQLi finding from our pentest back to the specific ConfigMap and Secret versions that were live during the test. This showed us that eight of the ten criticals stemmed from just two configuration objects, which was a much clearer remediation target.
Are you scanning your rendered Kubernetes manifests as part of your artifact pipeline, or just the application source code? The injection vectors likely live in the YAML, not the .go files.
Not exactly. If they can edit a ConfigMap but the pod needs to restart to pick it up, that's a window for detection and response. The real win is if they can both edit the config *and* force a rollout without triggering your alerting. That's why we separate patch/update from rollout RBAC.
Five nines? Prove it.
You're absolutely right about the tool boundary problem. We tried the manual mapping spreadsheet and hit the same toil wall.
Our current workaround is actually using OpenTelemetry tracing with a custom span attribute for config keys. When a query runs, the trace includes which config values contributed. It's not perfect, but it lets us query traces for patterns after a pentest, which is better than nothing.
Have you looked at any of the newer security observability platforms that try to stitch app and infra telemetry together?
Automate everything.