Introduction
The exampleSite/config/_default/params.toml file in this Hugo-based project is responsible for configuring site-wide parameters — including the Google Maps integration used to display an interactive map widget. At line 113, a single configuration entry quietly sat with a value that would make any security engineer wince:
map_api_key = "AIzaSyCcABaamniA6OL5YvYSpB3pFMNrXwXnLwU"
This is not a placeholder. It is not a test key. It is a real, live Google Maps API key committed directly to version control — fully visible to anyone who clones the repository, browses the GitHub interface, or accesses the deployed site's source. The moment this key was pushed to a public (or even a semi-public internal) repository, the clock started ticking on potential abuse.
This post breaks down exactly how this happened, what an attacker could do with it, and how the fix eliminates the risk entirely.
The Vulnerability Explained
What Was in the File
In exampleSite/config/_default/params.toml, the Google Maps configuration block looked like this before the fix:
# google map
[google_map]
enable = false
map_api_key = "AIzaSyCcABaamniA6OL5YvYSpB3pFMNrXwXnLwU"
map_latitude = "51.5223477"
map_longitude = "-0.1622023"
map_marker = "images/marker.png"
The key AIzaSyCcABaamniA6OL5YvYSpB3pFMNrXwXnLwU follows the well-known format of Google Maps JavaScript API keys (AIza prefix followed by 35 alphanumeric characters). Automated secret scanners — and even a casual human reviewer — can immediately identify this pattern.
Why enable = false Doesn't Help
You might notice that enable = false is set in the same block. This might seem like a mitigating factor — if the map feature is disabled, is the key really exposed? The answer is an emphatic yes, for two reasons:
- The key exists in the file regardless of the
enableflag. The configuration file is committed to the repository. Any attacker who reads the file sees the key, whether the feature is enabled or not. - API keys are not scoped to your application's runtime state. Google's API servers have no idea your Hugo site has
enable = false. The key works independently of your application logic.
The Specific Exploit Path
Here is a concrete attack scenario using this exact vulnerability:
- An attacker visits the GitHub repository (or any public mirror) and navigates to
exampleSite/config/_default/params.toml. - They read line 113:
map_api_key = "AIzaSyCcABaamniA6OL5YvYSpB3pFMNrXwXnLwU". - They make a direct HTTP request to the Google Maps Geocoding API:
https://maps.googleapis.com/maps/api/geocode/json?address=London&key=AIzaSyCcABaamniA6OL5YvYSpB3pFMNrXwXnLwU - If the key has not been restricted by IP or HTTP referrer, the request succeeds — and the API call is billed to the key owner's Google Cloud account.
- The attacker scripts thousands of such requests, exhausting the quota or generating significant charges before the owner notices.
Beyond billing fraud, depending on which Google APIs the key is authorized for, an attacker might also access Maps Embed API, Places API, Directions API, or other services — potentially exposing sensitive location data or functionality.
Real-World Impact
- Unexpected billing charges: Google Maps API calls are billed per request. A single compromised key can generate hundreds or thousands of dollars in charges overnight.
- Quota exhaustion: Legitimate users of the site's map feature would find the feature broken once the quota is consumed.
- Reputation damage: If the key is associated with a business account, abuse could trigger account suspension.
- Compliance implications: Exposed credentials in a repository may violate internal security policies or regulatory requirements.
This vulnerability maps to CWE-798: Use of Hard-coded Credentials, one of the most consistently exploited categories in the CWE Top 25.
The Fix
What Changed
The fix is surgical and unambiguous. In exampleSite/config/_default/params.toml at line 113, the hardcoded key was replaced with an empty string and a clarifying comment:
Before (vulnerable):
map_api_key = "AIzaSyCcABaamniA6OL5YvYSpB3pFMNrXwXnLwU"
After (fixed):
map_api_key = "" # Replace with your Google Maps API key
Why This Fix Works
By replacing the key with an empty string, the fix achieves several things simultaneously:
- Eliminates the exposed credential from the codebase. Future clones of the repository will not contain a usable API key.
- Preserves the configuration structure. The
map_api_keyfield still exists, so developers know exactly where to supply their own key. No configuration schema changes are required. - Provides clear guidance. The inline comment
# Replace with your Google Maps API keytells contributors what to do without leaving them guessing.
What You Should Do Next
The fix removes the key from the current HEAD of the repository, but the key still exists in git history. If this repository was ever public or shared, the key must be considered fully compromised. The correct remediation steps are:
- Immediately revoke the exposed key in the Google Cloud Console. Do not wait.
- Generate a new API key with appropriate restrictions (HTTP referrer restrictions, API restrictions).
- Purge the key from git history using
git filter-branchor the BFG Repo Cleaner. - Inject the new key at runtime using environment variables or a secrets manager rather than hardcoding it.
For Hugo sites specifically, environment variable substitution can be handled at build time:
# In your CI/CD pipeline or local .env (never committed)
export GOOGLE_MAPS_API_KEY="your-new-key-here"
Then reference it in your Hugo configuration using Hugo's environment variable support or a build script that populates the value before rendering.
Prevention & Best Practices
Never Commit Real Credentials to Source Control
This sounds obvious, but it happens constantly — especially in example sites, demo configurations, and documentation. The exampleSite/ directory in this repository is meant to demonstrate the theme, but it still gets committed, cloned, and sometimes deployed.
Rule of thumb: If a file is tracked by git, it should never contain a real secret. Period.
Use a .gitignore and Secret Templates
Maintain a params.toml.example with placeholder values and add the real params.toml to .gitignore:
# .gitignore
exampleSite/config/_default/params.toml
Then provide params.toml.example as the committed template:
map_api_key = "" # Set via environment variable GOOGLE_MAPS_API_KEY
Restrict API Keys at the Google Cloud Console
Even if you handle secrets correctly, always restrict your Google Maps API keys:
- Application restrictions: Limit to specific HTTP referrers (your domain only).
- API restrictions: Limit to only the APIs your application actually uses.
A restricted key that leaks is far less dangerous than an unrestricted one.
Pre-commit Hooks and CI Secret Scanning
Add secret detection to your development workflow:
# Install gitleaks
brew install gitleaks
# Scan repository
gitleaks detect --source . --verbose
Or use a pre-commit hook with detect-secrets:
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
GitHub also offers built-in secret scanning that detects Google API key patterns automatically.
OWASP and CWE References
This vulnerability falls under:
- OWASP A07:2021 – Identification and Authentication Failures (credential exposure)
- OWASP Secrets Management Cheat Sheet
- CWE-798: Use of Hard-coded Credentials
- CWE-312: Cleartext Storage of Sensitive Information
Key Takeaways
enable = falsedoes not protect a hardcoded API key — the credential is exposed in the file regardless of whether the feature is active in your application.- The
exampleSite/directory is still part of your repository — demo and example configurations are just as dangerous as production configs when they contain real credentials. - Revoking the key is step one, not the only step — git history must also be purged, or the key remains accessible to anyone who cloned the repo before the fix.
- The
map_api_keyfield inparams.tomlshould always be empty in committed files — real values belong in environment variables or a secrets manager, injected at build or deploy time. - Automated scanning catches what code review misses — this key sat at line 113 of a configuration file that humans routinely skim past; automated tools flag the
AIzaprefix immediately.
How Orbis AppSec Detected This
- Source: The hardcoded string
"AIzaSyCcABaamniA6OL5YvYSpB3pFMNrXwXnLwU"assigned tomap_api_keyinexampleSite/config/_default/params.toml:113. - Sink: The credential value is directly readable by anyone with repository access — no exploit chain required; the secret is the vulnerability.
- Missing control: No environment variable substitution, no secrets manager integration, and no
.gitignoreexclusion prevented the real API key from being committed. - CWE: CWE-798 — Use of Hard-coded Credentials.
- Fix: The hardcoded key
AIzaSyCcABaamniA6OL5YvYSpB3pFMNrXwXnLwUwas replaced with an empty string""and a developer-facing comment instructing safe substitution.
Orbis AppSec automatically detected this vulnerability and opened a pull request with the fix. Try Orbis AppSec on your repositories to find and fix issues like this automatically.
Conclusion
A single line in a configuration file — map_api_key = "AIzaSyCcABaamniA6OL5YvYSpB3pFMNrXwXnLwU" — represented a critical security exposure that could have led to unauthorized API usage, unexpected billing charges, and quota exhaustion. The fix is straightforward: replace the hardcoded value with an empty placeholder and inject the real credential securely at runtime.
What makes this vulnerability particularly instructive is how easy it is to overlook. The exampleSite/ directory feels like demo code. The enable = false flag creates a false sense of safety. But from an attacker's perspective, the key is just a string in a text file — and text files in git repositories are universally readable.
The lesson is clear: treat every file in your repository as potentially public, use automated secret scanning in your CI pipeline, and never let a real credential touch version control.
References
- CWE-798: Use of Hard-coded Credentials
- CWE-312: Cleartext Storage of Sensitive Information
- OWASP Secrets Management Cheat Sheet
- Google Cloud: API Key Best Practices
- Semgrep rules for hardcoded secrets
- BFG Repo Cleaner — remove secrets from git history
- fix: a hardcoded google maps api key is exposed in t... in params.toml