Back to Blog
critical SEVERITY8 min read

How Plaintext Credential Storage happens in JSON Configuration Files and how to fix it

A critical security issue was discovered in `assets/settings/global.json` where a real phone number (PII) was stored in plaintext alongside placeholder patterns for API keys and payment credentials. This design encouraged developers to substitute real credentials directly into a version-controlled file, creating a high risk of credential exposure via repository access or filesystem reads. The fix replaces the hardcoded phone number with a placeholder and reinforces safe configuration patterns.

O
By Orbis AppSec
Published August 15, 2026Reviewed August 15, 2026

Answer Summary

This vulnerability is a plaintext credential and PII exposure issue (CWE-312) in a JSON configuration file (`assets/settings/global.json`). The file stored a real phone number in the `dono1` field and used a placeholder pattern (e.g., `_COLE_SUA_KEY_AQUI_`) that encouraged substituting real API keys directly into a version-controlled file. The fix replaces the hardcoded phone number with a safe placeholder (`_SEU_NUMERO_AQUI_`) and removes the real PII from the codebase, preventing accidental credential commits and filesystem-based credential theft.

Vulnerability at a Glance

cweCWE-312
fixReplace hardcoded phone number with a placeholder string; enforce environment-variable-based credential injection
riskReal phone number and API keys exposed via version control or filesystem access
languageJSON / Node.js
root causeHardcoded PII and insecure placeholder pattern in a production configuration file committed to version control
vulnerabilityPlaintext PII and Credential Exposure in Configuration File

How Plaintext Credential Storage Happens in JSON Configuration Files and How to Fix It


The Problem in Plain Sight

Configuration files are often the most overlooked attack surface in a codebase. They sit quietly in the repository, rarely reviewed in security audits, yet they can hold some of the most sensitive data in your application. In this case, assets/settings/global.json did exactly that — it stored a real phone number in the dono1 field and established a placeholder pattern for API keys that practically invited developers to commit real credentials to version control.

This post breaks down exactly what went wrong, why it matters, and what the fix looks like — with concrete code references from the actual pull request.


Introduction

The assets/settings/global.json file serves as a central configuration store for the application, holding everything from API keys (including a Gemini API key field, API_KEY_GEMINI) to owner contact numbers (dono1 through dono4). While most fields used placeholder strings like _COLE_SUA_KEY_AQUI_ ("put your key here" in Portuguese), the dono1 field at line 19 contained a real, live phone number: 559284818701.

This is a textbook example of PII (Personally Identifiable Information) exposure — a real phone number, likely a Brazilian mobile number based on the 55 country code and 92 area code prefix, committed directly into a production codebase.

Beyond the PII issue, the broader design pattern is dangerous: the file's placeholder convention (_COLE_SUA_KEY_AQUI_) is a ticking time bomb. Any developer following the pattern will substitute real API keys and credentials directly into this file — a file that lives in version control, gets cloned by every contributor, and may be accessible on the production filesystem.


The Vulnerability Explained

What Was in the File

Here is the relevant section of assets/settings/global.json before the fix:

{
    "API_KEY_GEMINI": "_COLE_SUA_KEY_AQUI_",
    "listanegra_global": [],
    "blockcmd_global": [],
    "dono1": "559284818701",
    "dono2": "...",
    "dono3": "...",
    "dono4": "..."
}

Two distinct problems exist here:

  1. Hardcoded PII: The value 559284818701 is a real phone number stored in the dono1 field. This is PII under GDPR, LGPD (Brazil's data protection law), and most other privacy frameworks.

  2. Dangerous placeholder pattern: Fields like API_KEY_GEMINI use Portuguese-language placeholders (_COLE_SUA_KEY_AQUI_ = "put your key here"). This is an implicit instruction to developers to replace these values with real credentials — in the same file — which will then be committed to version control.

Why This Is Exploitable

The exploitation scenario is straightforward and requires no sophisticated tooling:

  1. Repository exposure: If the repository is public, or if an attacker gains read access to a private repository (via a leaked token, insider threat, or misconfigured CI/CD system), they can clone the repo and read assets/settings/global.json directly. Any real credentials substituted for the placeholders are immediately exposed.

  2. Filesystem access: On a deployed server, if an attacker achieves path traversal (e.g., via a misconfigured web server or a directory traversal vulnerability in the Node.js application), they can read the JSON file and extract all credentials in cleartext.

  3. PII harvesting: The phone number in dono1 can be harvested for spam, phishing, or social engineering attacks against the owner of that number.

  4. Downstream consumer risk: This is described as a Node.js library. Every downstream project that installs this package and follows the placeholder substitution pattern will inherit the same vulnerability in their own deployments.

The vulnerability is classified under CWE-312: Cleartext Storage of Sensitive Information — the system stores sensitive data (PII and potentially API keys) without any cryptographic protection, making it trivially readable by anyone with file or repository access.

Notably, the PR description also mentions that PBKDF2 is available in the Rust dependencies (src-tauri/Cargo.lock:3809) and that getToken/setToken functions in plugins/auth-oauth2/src/store.ts write credentials to disk without encryption — a related but separate issue that reinforces the pattern of insecure credential handling across this codebase.


The Fix

What Changed

The fix is surgical and targeted. A single line in assets/settings/global.json was changed:

Before:

"dono1": "559284818701",

After:

"dono1": "_SEU_NUMERO_AQUI_",

The real phone number 559284818701 is replaced with the placeholder _SEU_NUMERO_AQUI_ ("your number here" in Portuguese), consistent with the placeholder convention used by other fields in the file.

Why This Matters

This change accomplishes two things immediately:

  1. Removes PII from version control: The real phone number is no longer in the git history going forward. (Note: a full remediation should also include a git history rewrite or at minimum a warning that the number exists in prior commits.)

  2. Reinforces the placeholder pattern as the correct baseline: By ensuring all sensitive fields use placeholder values in the committed file, the repository no longer contains any real sensitive data by default. Developers are reminded to substitute values locally, not in the committed file.

What the Fix Does NOT Do (And What Else You Should Do)

The placeholder fix is a necessary first step, but it does not fully solve the underlying design problem. The placeholder pattern itself is inherently risky because it relies on developer discipline. A more robust solution involves:

  • Environment variables: Load sensitive values like API_KEY_GEMINI and owner phone numbers from environment variables (process.env.API_KEY_GEMINI) rather than from a JSON file.
  • Secrets manager integration: Use a service like AWS Secrets Manager, HashiCorp Vault, or Doppler to inject credentials at runtime without ever writing them to disk or to version control.
  • .gitignore for local overrides: Provide a global.json.example with placeholders (committed), and instruct developers to create a local global.json (gitignored) with real values.

Key Takeaways

  • The dono1 field in global.json contained a real Brazilian phone number — a direct PII violation that required immediate removal from the codebase and its git history.
  • The _COLE_SUA_KEY_AQUI_ placeholder pattern is dangerous by design: it instructs developers to write real credentials into a version-controlled file, making credential exposure a matter of when, not if.
  • JSON configuration files committed to version control should never contain real credentials or PII — not even temporarily, because git history is permanent.
  • The presence of PBKDF2 in src-tauri/Cargo.lock but its absence in plugins/auth-oauth2/src/store.ts highlights a broader pattern of available-but-unused cryptographic tooling in this codebase.
  • Downstream consumers of this Node.js library inherit the risk: any project following the placeholder substitution pattern will expose their own credentials in the same way.

How Orbis AppSec Detected This

  • Source: The dono1 field at line 19 of assets/settings/global.json, where a real phone number (559284818701) was stored as a literal string value in a version-controlled production configuration file.
  • Sink: Any filesystem read of assets/settings/global.json — whether via direct repository access, a cloned copy, or a path traversal exploit against the deployed application.
  • Missing control: No secrets scanning pre-commit hook, no environment variable injection pattern, no encryption of sensitive fields, and no .gitignore rule to prevent the file with real values from being committed.
  • CWE: CWE-312 — Cleartext Storage of Sensitive Information.
  • Fix: The hardcoded phone number 559284818701 in the dono1 field was replaced with the placeholder _SEU_NUMERO_AQUI_, removing PII from the repository and reinforcing the safe placeholder baseline.

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 vulnerability in assets/settings/global.json is a reminder that configuration files are code — they deserve the same scrutiny as any .ts or .js file in your project. A single hardcoded phone number and a well-intentioned placeholder pattern created a setup where real PII and API credentials were one developer substitution away from living permanently in version control.

The fix is simple: replace real values with placeholders, move secrets to environment variables, and add pre-commit scanning to catch anything that slips through. For credentials that must be stored on disk, leverage the cryptographic libraries already in your dependency tree — PBKDF2 is right there in Cargo.lock, waiting to be used.

Security in configuration management is not glamorous, but it is foundational. The most sophisticated encryption in your application means nothing if the API keys are sitting in a JSON file on GitHub.


Prevention and further reading

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #17

Related Articles

critical

deleteNestedProperty Prototype Pollution via Dot-Notation Path

The `deleteNestedProperty` function in propertyUtils.ts allowed attackers to manipulate JavaScript object prototypes by passing specially crafted dot-notation paths like `__proto__.polluted`. A fix now blocks dangerous keys before processing, preventing prototype pollution attacks that could affect all objects in the application.

high

How Denial of Service via Infinite Loop Happens in JavaScript Dependencies and How to Fix It

CVE-2026-67213 is a high-severity denial of service vulnerability in nanoid before version 5.1.6 that triggers an infinite loop during random ID generation when processing specially crafted input. We upgraded nanoid across the entire dependency tree to patch this flaw and prevent attackers from freezing application threads. This fix ensures that ID generation remains resilient even when handling adversarial input patterns.

high

How Sensitive Data Exposure happens in Zotero plugins and how to fix it

A high-severity data exposure vulnerability in `Zotero.ts` automatically transmitted complete document metadata—including private notes, attachment paths, and tags—to external LLM services without user consent. The fix replaces broad `item.toJSON()` serialization with explicit field selection, sending only essential bibliographic data.

high

How missing dependency update cooldowns happen in GitHub Dependabot configurations and how to fix it

A semgrep scan flagged `.github/dependabot.yml` for lacking a cooldown period, meaning Dependabot would immediately propose updates to brand-new package versions across npm, Bundler, and Docker ecosystems. The fix adds a `cooldown: default-days: 7` block to every `package-ecosystem` entry, forcing a one-week waiting period before newly published releases are considered — reducing exposure to malicious or unstable package drops.

high

How Path Traversal Happens in TensorFlow's Data Service and How to Fix It

TensorFlow's data service dispatcher validated dataset IDs against forward-slash traversal attacks but overlooked backslash characters on non-Windows platforms, allowing attackers to escape the root directory. A targeted fix adds explicit backslash validation across all platforms, closing a high-severity path traversal vulnerability in the snapshot management system.

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.