VNX-SEC-068: Ethereum private key
Detects 64-hex Ethereum private keys assigned to a private-key name, passed to a wallet, signer or transaction-signing call, or listed in a Hardhat accounts array.
| Field | Value |
|---|---|
| Rule ID | VNX-SEC-068 |
| Severity | Critical |
| SARIF level | error |
| Kind | secrets |
| Languages | Any file |
| CWE | CWE-798 |
| CAPEC | CAPEC-191 |
| ATT&CK | T1552.001 |
| CWSS vector | CWSS:1.0/TI:C/AP:A/AL:A/IC:N/FC:LT/RP:N/RL:A/AV:I/AS:N/IN:A/SC:A/BI:C/DI:H/EX:H/EC:N/P:W |
| Tags | secrets ethereum crypto blockchain credentials |
| Source | internal/sast/rules/vnx-sec-068.rego |
Overview
This rule reports exactly 64 hexadecimal characters (optionally 0x-prefixed) used as an Ethereum private key: assigned to a private-key name (PRIVATE_KEY, privateKey, DEPLOYER_PRIVATE_KEY, signer_key…) in code, JSON/YAML or .env files; passed to new ethers.Wallet, privateKeyToAccount, Account.from_key, go-ethereum crypto.HexToECDSA, web3j Credentials.create, fromPrivateKey, SigningKey, PrivateKey, Truffle HDWalletProvider, web3.js wallet.add, or Rust LocalWallet/PrivateKeySigner (from_str, .parse::<LocalWallet>()); passed as the key argument of signTransaction / sign_transaction; or listed in a Hardhat/Truffle accounts: [...] array. The key is masked in the snippet.
A bare 64-hex value is not a key: transaction and block hashes, bytes32 constants, storage slots and role ids are not reported. Neither are keys read from the environment, the published Hardhat/Anvil development keys, placeholders (0x000...), comment lines, Markdown, and test, fixture, vendored and generated files. Encrypted V3 keystore files are VNX-SEC-700.
What Gets Flagged
const wallet = new ethers.Wallet("0x<64 hex characters>", provider);
DEPLOYER_PRIVATE_KEY=<64 hex characters>
Not flagged:
const TX_HASH = "0x<64 hex transaction hash>";
const wallet = new ethers.Wallet(process.env.PRIVATE_KEY, provider);
Why This Matters
Hardcoded ethereum private key values are routinely scraped by automated bots within minutes of a public push, and then used to access the account, exfiltrate data, or pivot into downstream services. Once the credential is in git history it is permanently in third-party hands.
Remediation
- Revoke the leaked credential in the provider’s console immediately.
- Replace with a short-lived alternative, OAuth 2.0 access tokens, IAM role assumption, OIDC federation, wherever the platform supports it.
- Store the new credential in a secrets manager (AWS Secrets Manager, HashiCorp Vault, GitHub Actions secrets, Doppler).
- Audit the provider’s access logs for activity you did not initiate between the leak and the revocation.
- Purge from git history with
git filter-repoor BFG, then re-scan with gitleaks/truffleHog to confirm no other secrets remain. - Enable push protection so future commits are blocked at the developer machine.
References
- CWE-798: Use of Hard-coded Credentials
- gitleaks
- truffleHog
- OWASP Credentials Management Cheat Sheet
- MITRE ATT&CK T1552.001 – Credentials In Files
- git-filter-repo
Suppressing this rule
Put a nosec comment on the line, or on line 1 to cover the whole file. Use the comment marker of the file’s language (#, //, -- or ;):
# nosec vnx-sec-068
// nosec vnx-sec-068
Or record an ignore rule: vulnetix ignore add --rule vnx-sec-068 --reason "...". See Suppressing findings.