All Articles
SecurityPost-MortemSecrets

A Hardcoded Credential Cost a Client €1.2M. Here's the 20-Minute Fix They Skipped.

A single committed secret turned into a seven-figure incident. The prevention was twenty minutes of tooling setup. Here's exactly what happened and what to do instead.

MGMohamed Ghassen BrahimMay 28, 20268 min read

A single hardcoded API key committed to a private GitHub repository became a €1.2 million incident. The tooling that would have prevented it takes twenty minutes to set up and costs nothing. That gap — twenty minutes of setup versus seven figures of damage — is the whole argument for taking secrets management seriously before something forces you to.

I was engaged by a mid-market SaaS company — B2B, around €18M ARR, operating in the financial services data space — after the incident had already happened. My role was to lead the post-incident response, assess the full blast radius, and design the controls that should have been in place. What I found was a company that was not careless about security in general. They had endpoint detection, a reasonable vulnerability management programme, and a SOC2 Type II certification in progress. What they had was one gap — secrets in version control — and that gap cost them more than any of their existing controls were worth.

€1.2M
Total incident cost
Regulatory fine + remediation + commercial impact
~20 min
To set up prevention tooling
Pre-commit hooks + secrets scanner
11 days
Credential exposed before detection
Automated exfiltration began within hours
0
Alerts fired during exposure
No scanning policy was in place

What Actually Happened

A senior engineer was debugging a third-party financial data API integration. Under time pressure — they were trying to resolve a production incident with a data feed — they hardcoded the production API key directly into a configuration file to eliminate a potential environment-variable loading issue from their investigation scope. They resolved the incident. They committed the debugging code with the credential still in it. They pushed to the main branch of a private repository.

The repository was private. The key was not rotated. No secrets scanning was configured. There were no pre-commit hooks. The commit sat on main for eleven days.

What nobody at the company knew was that they had an undiscovered GitHub App OAuth token exposure from a separate, earlier incident — a misconfigured CI integration that had given an attacker read access to their private repositories. That access had been sitting dormant. When the credential appeared in the repository, automated tooling on the attacker's side — and this kind of automated scanning of compromised repository access is not sophisticated, it is commodity — detected it within hours and began exfiltrating financial data from the third-party API.

Eleven days later, the third-party API provider's fraud detection flagged anomalous access patterns and notified the company. By then, approximately 340,000 customer financial records had been accessed using the compromised key. The key was rotated immediately. The investigation began.

The full attack chain looked like this:

The €1.2M Breakdown

This is not a round number for rhetorical effect. The breakdown matters because it shows where the cost actually lands — and most of it is not in the places companies typically imagine when they think about security incidents.

Cost CategoryAmountNotes
GDPR regulatory fine€480,000Supervisory authority found inadequate technical controls
External forensic investigation€210,0006-week engagement to establish full data access scope
Third-party legal counsel€95,000Regulatory response, data subject notification compliance
Customer notification programme€68,000Statutory notification to affected data subjects
Commercial impact — churned contracts€290,000Two enterprise contracts not renewed in the quarter following disclosure
Internal engineering remediation€57,000Estimated cost of 8 weeks of senior engineering time
Total€1.2MExcludes reputational damage not yet fully quantified

The fine is significant. But the churned contracts and the remediation cost together are larger — and those are the costs that leadership had not anticipated when they were mentally modelling the "worst case" for a security incident.

The forensic investigation was expensive because the company did not have centralised audit logging of API access patterns. Establishing what had been accessed required reconstructing activity from third-party API provider logs, internal application logs, and network flow data — a process that would have taken a fraction of the time with proper audit log retention in place.

⚠️

The fine was for inadequate controls, not the breach itself

The regulatory finding was not simply that a breach occurred. The finding was that the company lacked adequate technical controls to prevent secrets from entering version control — despite operating a platform that processed personal financial data. The absence of pre-commit scanning was specifically cited. If the controls had been in place and circumvented, the regulatory outcome would likely have been materially different.

The 20-Minute Fix

The specific tooling that would have caught this credential before it reached the repository:

Step 1: Install a pre-commit secrets scanning hook (10 minutes)

detect-secrets (from Yelp, open source, actively maintained) or gitleaks (Go-based, slightly faster, also open source) can be installed as a pre-commit hook in under ten minutes. Both maintain patterns for API keys, OAuth tokens, private keys, database connection strings, and cloud provider credentials.

pip install detect-secrets
detect-secrets scan > .secrets.baseline

Then configure the hook in .pre-commit-config.yaml and add the baseline file to the repository. Every subsequent commit is scanned before it reaches the remote. A detected secret blocks the commit and shows the developer exactly where it is.

Step 2: Enable repository-level scanning (5 minutes)

GitHub's secret scanning is enabled at the repository or organisation level via a settings toggle. It takes less than five minutes. It scans all historical commits and all future pushes for a large library of partner-defined credential patterns. It fires an alert when a match is found. It is free for public repositories and included in GitHub Advanced Security for enterprise.

This is the backstop. It catches what pre-commit hooks miss — which is typically credentials committed from machines where the hook isn't installed (new developer laptops, CI runners committing generated files, scripts pushing via API).

Step 3: Add credential rotation to your incident response playbook (5 minutes of configuration)

If a secret is ever committed, the response needs to be automatic and immediate. Set up a runbook that rotates any committed credential within 15 minutes of detection — not within one business day, not "as soon as someone picks it up." Automated tooling exists for this for most major API providers.

💡

Pre-commit hooks only protect machines where they're installed

The canonical failure mode for pre-commit hooks is a developer committing from a machine where the hook isn't set up — a new laptop, a cloud IDE, a shared workstation. Enforce hook installation in your onboarding checklist AND use repository-level scanning as the organisation-wide backstop. Neither alone is sufficient; together they close the gap.

The Deeper Failure: No Secrets Management Strategy at All

The pre-commit hook is the tactical fix. The strategic failure behind this incident was the absence of any coherent secrets management posture.

The company was using a mix of environment variables in CI/CD pipeline settings, plain text .env files (gitignored, mostly), a small number of AWS Secrets Manager entries for the most sensitive production credentials, and — as this incident demonstrated — ad hoc hardcoding when convenience trumped process under pressure.

That patchwork is extremely common in companies that grew fast and prioritised shipping. It is also a time bomb. The credential that caused this incident was not even a core production secret — it was a third-party API key that the team considered "less sensitive" than database credentials. That categorisation missed the point: any credential that grants access to customer data is sensitive, regardless of where it sits in the internal hierarchy.

Secrets TierWhat Belongs HereRecommended Storage
Tier 1 — CriticalDatabase master credentials, signing keys, root tokensDedicated vault (HashiCorp Vault, Azure Key Vault) with audit logging
Tier 2 — HighThird-party API keys with data access, OAuth secrets, service account keysSecrets manager with access controls and rotation policy
Tier 3 — StandardInternal service tokens, feature flag keys, non-sensitive configCI/CD secrets store, never in version control
NeverAnythingHardcoded in source, .env files committed, config files without gitignore

The principle is simple: a secret in version control is a secret you should assume is compromised. Version control systems have complex access models, broad historical access, and are frequently synced to developer machines, CI systems, and third-party tooling. The blast radius of a repository being read by an attacker is vastly larger than most development teams assume.

What We Implemented After the Incident

Within two weeks of being engaged, we had deployed the following:

Immediate (week 1):

  • gitleaks pre-commit hooks installed across all developer machines, enforced via a CI gate that fails any push from a machine that doesn't have the hook version-pinned
  • GitHub Advanced Security secret scanning enabled organisation-wide, with alerts routing to a dedicated security Slack channel with 24/7 PagerDuty escalation
  • Full audit of all existing repositories using gitleaks in scan mode — we found four additional historical credential exposures, all of which were rotated immediately

Structural (week 2):

  • Migration of all Tier 1 and Tier 2 secrets to Azure Key Vault with managed identity access — no credential strings in CI/CD pipeline configuration
  • Automated credential rotation policy for all API keys: 90-day rotation for standard keys, 30-day for keys with customer data access
  • Developer security training session specifically on secrets hygiene — not generic security awareness, a targeted 45-minute session on this specific failure mode

The combination took approximately three weeks of focused work — mostly the secrets migration, not the scanning setup. The scanning setup genuinely took an afternoon.

🔍

The audit of historical repositories always finds something

In every post-incident engagement where I've run a retrospective scan of historical version control, we've found credentials from years ago that were never rotated. Most of them are harmless because the services they authenticated to have been decommissioned. Some are not. Run the historical scan. Rotate what you find. Do it before someone else finds it first.

What This Costs If You Don't Do It

The €1.2M figure is large enough to feel exceptional. It isn't. The median cost of a data breach for a mid-market company in the EU has been climbing consistently, and GDPR enforcement has matured to the point where "we didn't know our controls were inadequate" is not a mitigating argument — it is the finding.

The specific compounding factor in this incident was the pre-existing repository access that the company didn't know they had lost. That is not unusual. OAuth token exposures, misconfigured CI integrations, and overpermissioned GitHub Apps are extremely common in companies that have grown their engineering toolchain organically. A single committed secret, combined with an access vector the company didn't know existed, created an incident that eleven days of exposure turned into a regulatory event.

Twenty minutes of tooling. Eleven days of exposure. €1.2M.

The arithmetic is not ambiguous.


If you operate a platform that handles personal or financial data and you are not certain that secrets scanning is in place across your entire engineering organisation, the question is not whether this can happen to you — it is whether it already has and you don't know it yet.

Let's talk — book a 30-minute discovery call. I'll tell you honestly whether what you have in place is sufficient or whether you're one committed credential away from an incident you don't want to manage.

Ready to act

Ready to put this into practice?

I help companies implement the strategies discussed here. Book a free 30-minute discovery call.

Schedule a Free Call