Back to Blog
critical SEVERITY6 min read

How Hardcoded API Keys in WASM Modules Happen in KAP and How to Fix Them

A critical security vulnerability in `wasm/kap/standard-lib/fhelp-impl.kap` exposed hardcoded Gemini API keys directly in source code distributed to end users via WASM modules. The fix replaces the embedded credential with secure environment variable retrieval, preventing credential extraction through browser developer tools or binary inspection.

O
By Orbis AppSec
Published September 7, 2026Reviewed September 7, 2026

Answer Summary

Hardcoded API key exposure (CWE-798) in KAP/WASM applications occurs when credentials are embedded directly in source files that compile to WebAssembly and ship to browsers. The vulnerability in `fhelp-impl.kap:3257` stored a live Gemini API key (`AI..................................VyY`) in a comment and variable, exposing it to anyone inspecting the WASM binary. The fix replaces `apikey ← "AI..."` with `apikey ← env:get "GEMINI_API_KEY"`, moving secrets to environment variables outside the distributed codebase.

Vulnerability at a Glance

cweCWE-798 (Use of Hard-coded Credentials)
fixReplace hardcoded string with environment variable retrieval via `env:get`
riskComplete API key compromise for all users; unauthorized access to paid AI services; potential data exfiltration through compromised keys
languageKAP (APL-based array programming language, compiled to WASM)
root causeAPI key embedded directly in source code that compiles to client-distributed WASM
vulnerabilityHardcoded Secrets / Embedded Credentials

Title: How Hardcoded API Keys in WASM Modules Happen in KAP and How to Fix Them

In the wasm/kap/standard-lib/fhelp-impl.kap file of a KAP-based project, we discovered a critical hardcoded secrets vulnerability at line 3257 that exposed a live Gemini API key to every user who loaded the application. The gemini query function embedded credentials directly in source code that compiles to WebAssembly and ships to browsers—making extraction trivial through developer tools or binary inspection.

This vulnerability illustrates a dangerous anti-pattern: treating client-side code as a secure storage location for server-side secrets. When your build pipeline produces WASM modules for browser distribution, any string in your source becomes public knowledge.


The Vulnerability Explained

The Problematic Code

The vulnerable implementation in fhelp-impl.kap:3255-3262 contained a hardcoded API key for Google's Generative Language API:

∇ gemini query {
  ⍝ curl with your apikey to see the list of models:
  ⍝  https://generativelanguage.googleapis.com/v1beta/models?key=AI...
  model ← \"gemini-2.5-flash-preview-05-20\"
  url ← \"https://generativelanguage.googleapis.com/v1beta/models/\", model, \":generateContent?key=\"
  apikey ← \"AI..................................VyY\" ⍝ your API key goes here
  target_url ← url, apikey
  input ← \"{\\\"contents\\\":[{\\\"parts\\\":[{\\\"text\\\":\\\"\", query, \"\\\"}]}]}\"
  headrs ← \"Accept\" \"application/json\"

Two critical flaws exist here:

  1. The apikey variable (line 3259) contains a literal 39-character Google API key starting with AI and ending with VyY
  2. The commented URL (line 3257) includes a partial key leak in the example, reinforcing the pattern

Why WASM Makes This Especially Dangerous

KAP compiles to WebAssembly for browser execution. Unlike server-side code, WASM modules are:

  • Downloaded entirely to the client before execution
  • Inspectable through browser DevTools (Sources → WASM → disassembly)
  • Analyzable with standard tools like wasm2wat or binary scanners

An attacker needs only to:
1. Open browser developer tools on any page using this module
2. Search for the string AI or gemini in the WASM binary
3. Extract the complete key for unauthorized API access

Real-World Impact

For this specific application:

  • Financial exposure: Attackers could exhaust quota limits on the Gemini API, incurring costs for the key owner
  • Data poisoning: Malicious queries through the compromised key could train models on adversarial inputs
  • Rate limit exhaustion: Legitimate users would be denied service when quotas are consumed by attackers
  • Credential cascading: If the same key pattern was used elsewhere, additional services become compromised

The Fix

Before: Hardcoded Credential

  ∇ gemini query {
    ⍝ curl with your apikey to see the list of models:
    ⍝  https://generativelanguage.googleapis.com/v1beta/models?key=AI...
    model ← \"gemini-2.5-flash-preview-05-20\"
    url ← \"https://generativelanguage.googleapis.com/v1beta/models/\", model, \":generateContent?key=\"
    apikey ← \"AI..................................VyY\" ⍝ your API key goes here
    target_url ← url, apikey

After: Environment Variable Retrieval

   gemini query {
     curl with your apikey to see the list of models:
      https://generativelanguage.googleapis.com/v1beta/models?key=YOUR_API_KEY
    model  \"gemini-2.5-flash-preview-05-20\"
    url  \"https://generativelanguage.googleapis.com/v1beta/models/\", model, \":generateContent?key=\"
    apikey  env:get \"GEMINI_API_KEY\" ⍝ set this environment variable to your own API key
    target_url  url, apikey

Security Improvements

Aspect Before After
Key storage Embedded in source/WASM External environment variable
Distribution Shipped to all clients Never leaves server/build environment
Rotation Requires code change + redeploy Environment update only
User isolation Shared key across all users Each deployment uses own key
Audit trail Key visible in git history Key excluded from version control

The comment was also sanitized to use YOUR_API_KEY as a placeholder, preventing accidental copy-paste leaks.


Prevention & Best Practices

For KAP and WASM Projects

  1. Never embed credentials in compilable source: If it becomes WASM, it becomes public. Use build-time injection or server-side proxies instead.

  2. Use env:get for all secrets: KAP's env:get function retrieves values at runtime from the execution environment, keeping credentials out of distributed artifacts.

  3. Implement .env patterns with .gitignore:
    bash # .gitignore .env *.local secrets.kap

  4. Server-side proxy for browser WASM: Instead of calling APIs directly from WASM, route through your backend where secrets remain protected.

Detection Tools

Tool Type Implementation Detection Method
Pre-commit hooks gitleaks, truffleHog Entropy analysis + pattern matching for AIza[0-9A-Za-z\-_]{35}
CI/CD scanning GitHub Secret Scanning, GitLab Secret Detection Automated PR scanning for credential patterns
SAST Semgrep rules for hardcoded credentials AST-based detection of string literals assigned to apikey, token, secret
WASM analysis Custom scripts with wasm2wat Extract and scan all strings from compiled modules

Security Standards

  • CWE-798: Use of Hard-coded Credentials
  • CWE-259: Use of Hard-coded Password
  • OWASP Top 10 2021: A07:2021 – Identification and Authentication Failures
  • NIST SP 800-63B: Section 5.1.1.2 – Memorized Secret Verifiers (prohibits hardcoded credentials)

Key Takeaways

  • The gemini function in fhelp-impl.kap now retrieves API keys via env:get "GEMINI_API_KEY" instead of literal strings, eliminating credential exposure in WASM distributions

  • WASM binaries are not a secure storage medium—any string in your KAP source becomes extractable client-side through standard browser developer tools

  • Environment variables must be configured at build time for WASM, not runtime, requiring build pipeline changes to inject secrets securely

  • Comments containing partial credentials (⍝ https://...?key=AI...) leak key patterns and should use placeholder values like YOUR_API_KEY

  • Each deployment should use isolated credentials rather than shared keys embedded in distributed code, enabling per-environment rotation and breach containment


How Orbis AppSec Detected This

Source: The hardcoded string literal "AI..................................VyY" assigned to variable apikey in wasm/kap/standard-lib/fhelp-impl.kap:3259

Sink: The target_url ← url, apikey concatenation at line 3260, which embeds the credential into HTTP request URLs sent to Google's API

Missing control: No environment variable abstraction or build-time secret injection; direct use of string literal in production code distributed to client browsers

CWE: CWE-798 – Use of Hard-coded Credentials

Fix: Replaced the hardcoded apikey string with env:get "GEMINI_API_KEY" to retrieve credentials from environment configuration outside the distributed WASM module.

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

The hardcoded API key in fhelp-impl.kap demonstrates a fundamental misunderstanding of WASM's security model: client-side code cannot protect server-side secrets. When your build produces .wasm files for browser execution, every string, comment, and constant becomes part of the public attack surface.

The fix—migrating from apikey ← "AI...VyY" to apikey ← env:get "GEMINI_API_KEY"—restores proper credential hygiene by ensuring secrets never enter the distributed artifact. For teams shipping KAP or other languages to WASM, this pattern must be enforced through automated scanning, pre-commit hooks, and architectural reviews that treat all client-bound code as publicly readable.


References

Frequently Asked Questions

What is hardcoded secrets exposure in WASM?

It's when API keys, tokens, or passwords are embedded directly in source code that compiles to WebAssembly, making credentials visible to anyone who downloads and inspects the binary or source.

How do you prevent hardcoded secrets in KAP/WASM?

Use environment variable retrieval functions like `env:get` instead of string literals, store secrets in secure configuration outside the codebase, and implement pre-commit hooks to scan for credential patterns.

What CWE is hardcoded API key exposure?

CWE-798: Use of Hard-coded Credentials

Is obfuscation enough to prevent credential extraction from WASM?

No. WASM binaries can be decompiled and analyzed. Obfuscation only slows down attackers; determined adversaries can still extract embedded strings through static analysis or runtime debugging.

Can static analysis detect hardcoded secrets in KAP?

Yes. Pattern-based scanners can identify high-entropy strings matching API key formats, and semantic analysis can flag assignments to variables named `apikey`, `token`, or `secret`.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #170

Related Articles

critical

How Hardcoded API Key Exposure Happens in Node.js and How to Fix It

A critical vulnerability in `archive/open_claude_code/src/api/client.mjs` exposed five different API providers' credentials through direct `process.env` access. The fix introduced a centralized `readApiKey()` function to enforce secure credential retrieval across Anthropic, OpenAI, Google, and other integrations.

high

How Insufficiently Protected Credentials happens in Node.js and how to fix it

A regex-based guard in `skills/xmemo/scripts/xmemo-skill.mjs` was supposed to block sensitive credentials from being passed as CLI flags, but it only matched a handful of keyword patterns—missing `password`, `client-secret`, `access-token`, `xmemo-key`, and more. The fix expands the blocklist regex to cover these additional credential patterns, closing a gap that could let secrets end up in shell history and process listings.

critical

How Hardcoded Firebase API Keys Happen in JavaScript Service Workers and How to Fix Them

A production Firebase service worker file (`static/firebase-messaging-sw.js`) contained hardcoded API keys and project configuration directly in publicly accessible JavaScript — including a second, previously commented-out set of credentials from an older project. While Firebase web config values are technically public identifiers, pairing them with unrestricted Firebase projects or missing Security Rules turns them into an open door for push notification abuse, quota exhaustion, and unauthorize

critical

How hardcoded API key exposure happens in Node.js plugins and how to fix it

A critical hardcoded API key (`actor-studio-gpt-beta`) was discovered in the `src/plugins/llm/index.js` file of the Actor Studio application, granting anyone with source code access the ability to make unauthorized requests to the LLM service endpoints. The fix removes the default key from both the LLM class definition and the settings module, requiring the key to be explicitly configured through module settings instead.

high

How Insecure Credential Storage Happens in Node.js and How to Fix It

A critical vulnerability in the Google Vision translator module stored API keys in plaintext configuration files accessible to attackers with local filesystem access. The fix relocates the API key from the URL query parameter to a secure HTTP header, eliminating the exposure vector while maintaining full functionality.

critical

How SQL injection happens in Python DuckDB view creation and how to fix it

A critical SQL injection flaw in `python/src/idx/api.py:265` built five DuckDB `CREATE VIEW` statements with Python f-strings, interpolating a filesystem path directly into SQL text. The fix replaces the interpolated path with a bound parameter (`read_parquet(?)`) and moves the view names into a hardcoded, non-interpolated statement map — eliminating any path where filenames or directory values can alter SQL structure.