[Reachable] Fix CWE-328 (Weak Hash Algorithm) vulnerability in src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00708.java:53#732
Open
appsecai-app[bot] wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What we found
6a428858src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00708.java:53Description: Detected MD5 hash algorithm which is considered insecure. MD5 is not collision resistant and is therefore not suitable as a cryptographic signature. Use HMAC instead.
Vulnerable Code Path
java.security.MessageDigest.getInstance("MD5")— hardcoded weak hash algorithmrequest.getParameterValues("BenchmarkTest00708")flows throughThingFactory.createThing().doSomething(param)intobar, which is the data hashedpasswordFile.txtunderUtils.TESTFILES_DIR— security-sensitive storage context'Sensitive value ... hashed and stored'— cryptographic intent is data protection, not a non-security identifierWhy this matters
Risk if not fixed: A bare unkeyed digest over attacker-controlled user input remains a CWE-328 weak-hash finding regardless of algorithm strength. The output is entirely predictable from the input, providing no integrity guarantee against a motivated attacker who can pre-compute any desired hash value. An adversary can forge hash values, bypass integrity checks, or replay crafted inputs with known hashes.
Risk level: Medium — Should be addressed in regular security maintenance. Exploitation requires control of the servlet input (via HTTP request parameters), but the servlet is publicly accessible.
Context: This servlet hashes arbitrary user-supplied data for logging/benchmark purposes. The filename
passwordFile.txtand response message confirm the developer intent is security-sensitive data protection, not a non-security fingerprint.Why we're changing it
Status: Confirmed vulnerability requiring remediation.
Finding: Line 53 uses
java.security.MessageDigest.getInstance("MD5")— a bare (unkeyed) weak hash algorithm. Even if the algorithm were upgraded to SHA-256, a bareMessageDigestover attacker-controlled user input still constitutes a CWE-328 weak-hash finding because the digest output is entirely determined by the attacker's input with no secret component. The scanner explicitly requires HMAC as the remediation.Recommended Remediation: Replace
MessageDigest.getInstance("MD5")with a keyed-integrity primitive. For arbitrary user-supplied data (not passwords), use HMAC-SHA256 (Mac.getInstance("HmacSHA256")) with a server-side secret key. This binds the hash output to a secret that the attacker cannot control, preventing pre-computation and forgery.How we confirmed
Automated checks we ran:
MessageDigest.getInstance("MD5")in this file.LLM review of the diff:
Vulnerability Flow Diagram
%%{init: {'theme':'base','themeVariables':{'fontFamily':'ui-sans-serif, Inter, system-ui, sans-serif','primaryColor':'#EDE9FE','primaryTextColor':'#1A1A2E','primaryBorderColor':'#7C3AED','lineColor':'#5B21B6','secondaryColor':'#FEF3C7','tertiaryColor':'#DCFCE7'}}}%% flowchart TD subgraph Vulnerable["❌ Vulnerable Flow - CWE-328 Weak Hash"] A1["Attacker Input<br/>BenchmarkTest00708 param"] --> A2["doPost in<br/>BenchmarkTest00708.java"] A2 --> A3["MessageDigest.getInstance<br/>Line 53 - MD5 Algorithm"] A3 --> A4["md.update + digest<br/>Unkeyed bare digest"] A4 --> A5["💥 Attacker Pre-computes<br/>Any desired MD5 hash"] A5 --> A6["💥 Hash stored to<br/>passwordFile.txt - Forged"] end subgraph Fixed["✅ Fixed Flow - HmacSHA256"] B1["User Input<br/>BenchmarkTest00708 param"] --> B2["doPost in<br/>BenchmarkTest00708.java"] B2 --> B3["HMAC_SIGNING_KEY loaded<br/>from environment variable"] B3 --> B4{"Key present?"} B4 -->|"Missing or empty"| B5["🛡️ Fail Closed<br/>GeneralSecurityException"] B4 -->|"Key available"| B6["Mac.getInstance<br/>HmacSHA256 with secret key"] B6 --> B7["mac.init + update + doFinal<br/>Keyed HMAC output"] B7 --> B8["🛡️ Attacker Cannot Forge<br/>Hash bound to secret key"] end style A3 fill:#FFE5E5,stroke:#F65A5A,color:#000 style A5 fill:#FEF3C7,stroke:#F59E0B,color:#000 style A6 fill:#FEF3C7,stroke:#F59E0B,color:#000 style B3 fill:#EDE9FE,stroke:#7C3AED,color:#000 style B5 fill:#DCFCE7,stroke:#16A34A,color:#000 style B6 fill:#EDE9FE,stroke:#7C3AED,color:#000 style B8 fill:#DCFCE7,stroke:#16A34A,color:#000Vulnerable flow: src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00708.java:53
Weak Hash Algorithm
%%{init: {'theme':'base','themeVariables':{'fontFamily':'ui-sans-serif, Inter, system-ui, sans-serif','primaryColor':'#EDE9FE','primaryTextColor':'#1A1A2E','primaryBorderColor':'#7C3AED','lineColor':'#5B21B6','secondaryColor':'#FEF3C7','tertiaryColor':'#DCFCE7'}}}%% flowchart TD subgraph Vulnerable["❌ Vulnerable Flow - CWE-328 Weak Hash"] direction LR A1["Attacker Input<br/>BenchmarkTest00708 param"] --> A2["doPost in<br/>BenchmarkTest00708.java"] A2 --> A3["MessageDigest.getInstance<br/>Line 53 - MD5 Algorithm"] A3 --> A4["md.update(input)<br/>Unkeyed bare digest"] A4 --> A5["💥 Attacker Pre-computes<br/>Any desired MD5 hash"] A5 --> A6["💥 Hash stored to<br/>passwordFile.txt - Forged"] end Vulnerable ~~~ Fixed subgraph Fixed["✅ Fixed Flow - HmacSHA256"] direction LR B1["User Input<br/>BenchmarkTest00708 param"] --> B2["doPost in<br/>BenchmarkTest00708.java"] B2 --> B3["HMAC_SIGNING_KEY loaded<br/>from environment variable"] B3 --> B4{"Key present?"} B4 -->|"Missing or empty"| B5["🛡️ Fail Closed<br/>GeneralSecurityException"] B4 -->|"Key available"| B6["Mac.getInstance<br/>HmacSHA256 with secret key"] B6 --> B7["mac.update + doFinal<br/>Keyed HMAC output"] B7 --> B8["🛡️ Attacker Cannot Forge<br/>Hash bound to secret key"] end style A3 fill:#FFE5E5,color:#1A1A2E style A5 fill:#ffa94d,color:#000 style A6 fill:#ffa94d,color:#000 style B3 fill:#74c0fc,color:#000 style B5 fill:#DCFCE7,color:#000 style B6 fill:#74c0fc,color:#000 style B8 fill:#DCFCE7,color:#000How we fixed it
Root Cause
The servlet used
java.security.MessageDigestwith a bare (unkeyed) hash algorithm. Even after swapping MD5 for SHA-256, a bareMessageDigestover attacker-controlled user input remains a CWE-328 weak-hash finding because the digest output is entirely determined by the attacker's input — there is no secret component. The scanner explicitly requires HMAC as the remediation.Fix Approach
The
MessageDigestpath is replaced entirely withjavax.crypto.MacusingHmacSHA256. The HMAC key is loaded at runtime from theHMAC_SIGNING_KEYenvironment variable. Because the key is not attacker-controlled, an adversary cannot pre-compute or forge the resulting digest regardless of what input they supply. The catch clause is widened toGeneralSecurityExceptionto cover bothInvalidKeyException(frommac.init) andNoSuchAlgorithmException(fromMac.getInstance) under a single handler, preserving the existing error-handling structure.Alternatives Considered
Code Changes
The fix modifies
src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00708.java:Before:
After:
The catch clause is updated from
NoSuchAlgorithmExceptiontoGeneralSecurityExceptionto handle bothInvalidKeyExceptionandNoSuchAlgorithmException.Files changed in this pull request (derived from the generated diff):
src/main/java/org/owasp/benchmark/testcode/BenchmarkTest00708.javaVulnerabilities Addressed
CWE-328
Use Of Md5
How we checked this fix
Automated checks we ran:
javax.crypto.Macandjavax.crypto.spec.SecretKeySpecare available in Java 8+.LLM review of the diff:
Verification of fix completeness:
MessageDigest.getInstance("MD5")in this file.BenchmarkTest00708.java.Reachability analysis
Reachability: Reachable
At least one remediated finding has a traced attacker-controlled path to the vulnerable sink.
Status: Reachable (confidence 0.97, source: grounded call graph via Joern)
Exploitability score: 75/100
Rationale: The servlet endpoint is publicly accessible via HTTP POST. User input from
request.getParameterValues("BenchmarkTest00708")flows throughThingFactory.createThing().doSomething(param)directly into the hash sink at line 53. The grounded call graph confirms the entry point (doPost) reaches the vulnerable operation without guard conditions. An attacker can supply arbitrary input via the HTTP parameter and observe the resulting hash value written topasswordFile.txtor echoed in the response, enabling pre-computation and forgery attacks.Attack prerequisites:
BenchmarkTest00708request parameterpasswordFile.txtor ability to observe hash values in responsesConfidence breakdown:
How to verify
Manual Verification Steps
Inspect the fix in the diff:
MessageDigest.getInstance("MD5").Mac.getInstance("HmacSHA256")is used instead.HMAC_SIGNING_KEYenvironment variable.GeneralSecurityException.Verify environment variable contract:
Verify imports:
javax.crypto.Macandjavax.crypto.spec.SecretKeySpecare imported.java.nio.charset.StandardCharsetsis imported (used for UTF-8 encoding).Compile and run unit tests:
mvn clean compile.mvn test.Local runtime test (optional):
export HMAC_SIGNING_KEY=$(openssl rand -base64 32)passwordFile.txtis created/updated with hash output.Runnable Verification Script (click to expand)
Save this script and run with
bash verify_fix.sh:Before you merge
## How we fixed it: Confirm the fix addresses the root cause (unkeyed digest → keyed HMAC) and not just the symptom (MD5 → SHA-256).## How we checked this fix: Confirm the automated checks and LLM review are sufficient for your risk tolerance.## Reachability analysis: Confirm the attacker path (public HTTP endpoint → user parameter → hash sink) matches your understanding of the codebase.HMAC_SIGNING_KEYin all environments before merging:openssl rand -base64 32GeneralSecurityExceptionand return HTTP 500 for all hash requests until this variable is set.passwordFile.txt) stores hash values for logging/benchmark purposes only; existing entries written with the old algorithm remain in the file but are not read back by this code path.## How to verifyin your environment before merging.Learn more
This fix was generated by AppSecAI. Please review before merging.