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.

Prevention & Best Practices

Never Commit Real Credentials or PII

This sounds obvious, but the dono1 field shows how easy it is to slip a real value into a config file. Establish a pre-commit hook using a tool like git-secrets or truffleHog to scan for phone numbers, API key patterns, and other sensitive data before they reach the repository.

Use Environment Variables for Runtime Secrets

Instead of:

{
  "API_KEY_GEMINI": "_COLE_SUA_KEY_AQUI_"
}

Do this in your Node.js code:

const apiKeyGemini = process.env.API_KEY_GEMINI;
if (!apiKeyGemini) {
  throw new Error('API_KEY_GEMINI environment variable is not set');
}

This ensures the key is never written to any file in the repository.

Encrypt Credentials at Rest

As noted in the vulnerability description, PBKDF2 is already available in the Tauri Rust dependencies. For credentials that must be stored on disk (e.g., OAuth tokens via plugins/auth-oauth2/src/store.ts), use PBKDF2 or a similar KDF to derive an encryption key from a device-specific secret, then encrypt the credential before writing it to disk.

Rotate Exposed Credentials Immediately

If a real API key or phone number was ever substituted into global.json and committed, treat it as compromised. Rotate the API key immediately and notify the individual whose phone number was exposed.

Apply Principle of Least Privilege to Config Files

Ensure that assets/settings/global.json (and any local override containing real values) has filesystem permissions that restrict read access to the application process only. On Linux/macOS: chmod 600 global.json.

Relevant Standards

  • CWE-312: Cleartext Storage of Sensitive Information
  • OWASP A02:2021 – Cryptographic Failures: Covers failure to protect sensitive data at rest
  • OWASP Secrets Management Cheat Sheet: Guidance on handling secrets in applications

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.


References

Frequently Asked Questions

What is plaintext credential storage in configuration files?

It occurs when sensitive values like API keys, passwords, or personal data are written directly into configuration files (e.g., JSON, YAML) that may be committed to version control or left readable on the filesystem, exposing them to anyone with repository or file access.

How do you prevent plaintext credential storage in Node.js?

Use environment variables or a secrets manager (e.g., AWS Secrets Manager, HashiCorp Vault) to inject credentials at runtime. Never commit real credentials or PII to source files. Add `.env` and sensitive config files to `.gitignore`.

What CWE is plaintext credential storage?

CWE-312 (Cleartext Storage of Sensitive Information) covers storing sensitive data without encryption or obfuscation, which is exactly what happens when credentials are placed in plaintext JSON configuration files.

Is using placeholder strings enough to prevent credential exposure?

No. Placeholder patterns like `_COLE_SUA_KEY_AQUI_` only help if developers never substitute real values into the file. The safer approach is to remove credential fields from config files entirely and load them from environment variables or a secrets manager at runtime.

Can static analysis detect plaintext credential storage?

Yes. Tools like Semgrep, truffleHog, git-secrets, and GitHub's secret scanning can detect hardcoded credentials, phone numbers, and suspicious placeholder patterns in committed files. Orbis AppSec's multi-agent AI scanner flagged this exact pattern.

View the Security Fix

Check out the pull request that fixed this vulnerability

View PR #17

Related Articles

high

How Quadratic CPU Consumption Vulnerabilities Happen in JavaScript YAML Parsers and How to Fix Them

A high-severity denial-of-service vulnerability in js-yaml versions 3.x and 4.x allowed attackers to trigger quadratic CPU consumption through specially crafted YAML documents using the !!omap tag. This fix upgrades js-yaml from 4.1.1 to 4.3.1 and from 3.14.2 to 3.15.1, eliminating the algorithmic complexity attack vector that could freeze Node.js applications processing untrusted YAML input.

high

How javascript.lang.security.detect-child-process.detect-child-process happens in Node.js and how to fix it

A high-severity command injection vulnerability was discovered in `scripts/build.js` where `execSync` was called with string-interpolated arguments (`sourceDir` and `outputPath`) inside a shell command. By replacing `execSync` with `spawnSync` using an argument array (no shell), the fix eliminates the possibility of shell metacharacter injection while preserving identical build behavior.

high

How Command Injection happens in Node.js child_process and how to fix it

A command injection vulnerability in nix.js's Release class allowed potentially malicious input through the `arch` parameter to be executed via shell commands. The fix replaced `execSync()` with `execFileSync()`, eliminating shell interpretation and preventing command injection by passing arguments as an array instead of a concatenated string.

critical

How Sensitive Data Exposure in Error Logging happens in TypeScript/Deno and how to fix it

A critical vulnerability in Supabase Edge Functions allowed sensitive authentication errors and API credentials to leak through verbose error logging. The `cancel-subscription/index.ts` function logged full error objects to the console, potentially exposing Paddle API keys and auth tokens in deployment logs. The fix sanitizes all error messages to log only safe error text while preserving debugging capability.

critical

How HTTP Header Injection Happens in Go and How to Fix It

A critical vulnerability in the file upload handler allowed attackers to inject CRLF sequences into HTTP response headers through crafted filenames. The fix sanitizes user-supplied filenames before using them in Content-Disposition headers, preventing header injection attacks that could lead to cache poisoning, session fixation, or XSS.

critical

How Command Injection happens in Node.js shell-quote and how to fix it

A critical command injection vulnerability (CVE-2026-9277) was discovered in shell-quote versions prior to 1.8.4, where unescaped line terminators allowed attackers to inject arbitrary shell commands through crafted input strings. The fix pins shell-quote to version 1.9.0 via a `package.json` overrides directive in the FabricExample project, ensuring all transitive dependencies resolve to the patched version. Left unaddressed, this vulnerability could have allowed arbitrary code execution on any