# REPRO-2026-00107: Swiper Prototype Pollution ## Summary Status: published Severity: critical Type: security Confidence: Unknown ## Identifiers REPRO ID: REPRO-2026-00107 GHSA: GHSA-hmx5-qpq5-p643 CVE: CVE-2026-27212 ## Package Name: swiper Ecosystem: npm Affected: >= 6.5.1, < 12.1.2 Fixed: 12.1.2 ## Root Cause # Root Cause Analysis Report: GHSA-hmx5-qpq5-p643 ## Summary A prototype pollution vulnerability exists in the swiper npm package (versions >=6.5.1, < 12.1.2) that can be bypassed by modifying `Array.prototype.indexOf`. The vulnerability resides in `shared/utils.mjs` at line 94 where `indexOf()` is used to check whether user-provided input contains forbidden strings like `__proto__`. An attacker can override `Array.prototype.indexOf` to always return -1, causing the filter to incorrectly allow `__proto__` keys through, resulting in successful prototype pollution of `Object.prototype`. ## Impact - **Package:** swiper (npm package) - **Affected Versions:** >=6.5.1, < 12.1.2 - **Fixed In:** 12.1.2 - **Severity:** CRITICAL ### Risk and Consequences This is a prototype pollution vulnerability which can have severe security implications: 1. **Authentication Bypass** - Polluted prototypes can modify authentication logic 2. **Denial of Service** - Modified prototypes can cause application crashes or unexpected behavior 3. **Property Injection** - Arbitrary properties can be injected into all objects 4. **Logic Manipulation** - Application business logic can be altered through prototype manipulation Any application that processes attacker-controlled input using this package may be affected, particularly when using `extendDefaults()` or similar methods that merge user input with internal configuration objects. ## Root Cause ### Technical Explanation The vulnerability exists in the swiper package's utility functions, specifically in `shared/utils.mjs` around line 94. The code attempts to prevent prototype pollution by checking if input keys contain forbidden strings: ```javascript // Vulnerable pattern (conceptual) if (forbiddenKeys.indexOf(key) !== -1) { // Block the key } ``` The problem is that `indexOf()` is a method called on the `forbiddenKeys` array. Since `indexOf` is defined on `Array.prototype`, it can be globally overridden: ```javascript Array.prototype.indexOf = () => -1; ``` When this override is in place: 1. `forbiddenKeys.indexOf('__proto__')` returns `-1` (instead of the actual index) 2. The check `indexOf(...) !== -1` evaluates to `false` 3. The `__proto__` key is allowed through the filter 4. `Object.prototype` gets polluted with attacker-controlled properties ### Bypass Mechanism The exploit chain works as follows: 1. **Override Phase:** `Array.prototype.indexOf = () => -1;` 2. **Input Phase:** Attacker provides `{"__proto__":{"polluted":"yes"}}` 3. **Filter Bypass:** The `indexOf` check returns `-1`, so `__proto__` passes validation 4. **Merge Phase:** The library merges the malicious payload into the target object 5. **Pollution:** `Object.prototype.polluted` is set to `"yes"` 6. **Impact:** All objects now have the `polluted` property ### Fix Information The issue was fixed in version 12.1.2. The fix likely replaces the `indexOf()`-based check with a more robust approach that doesn't rely on prototype methods that can be overridden, such as: - Using `Object.prototype.hasOwnProperty.call()` checks - Using a `Set` with `has()` method - Using `includes()` from a frozen array - Implementing a custom comparison function that doesn't rely on prototype methods ## Reproduction Steps ### Script Reference The reproduction script is located at: `repro/reproduction_steps.sh` ### What the Script Does 1. Creates a temporary directory and initializes npm 2. Installs the vulnerable version of swiper (12.1.1) 3. Creates a test script that: - Imports the swiper package - Overrides `Array.prototype.indexOf` to always return `-1` - Checks `{}.polluted` before exploitation (should be `undefined`) - Calls `swiper.default.extendDefaults()` with a malicious payload containing `{"__proto__":{"polluted":"yes"}}` - Checks `{}.polluted` after exploitation - Restores the original `Array.prototype.indexOf` 4. Runs the test and reports results 5. Cleans up temporary files ### Expected Evidence of Reproduction When the vulnerability is present, the script outputs: ``` Before exploit: {}.polluted = undefined After exploit: {}.polluted = yes [VULNERABILITY CONFIRMED] Prototype pollution successful! Object.prototype was polluted with 'polluted' property. ``` The key indicator is that `{}.polluted` changes from `undefined` to `"yes"`, proving that `Object.prototype` was successfully polluted. ## Evidence ### Log Files - **Installation log:** `logs/npm_install.log` - **Test output:** `logs/test_output.log` ### Key Excerpts From `logs/test_output.log`: ``` Testing prototype pollution in swiper... Before exploit: {}.polluted = undefined After exploit: {}.polluted = yes [VULNERABILITY CONFIRMED] Prototype pollution successful! Object.prototype was polluted with 'polluted' property. ``` ### Environment Details - **Node.js Version:** v22.22.0 - **npm Version:** 10.9.4 - **Tested Package:** swiper@12.1.1 - **Operating System:** Linux (containerized environment) ## Recommendations / Next Steps ### Suggested Fix Approach 1. **Replace indexOf()-based checks** with alternatives that cannot be easily bypassed: ```javascript // Instead of: if (forbiddenKeys.indexOf(key) !== -1) // Use: const forbiddenSet = new Set(['__proto__', 'constructor', 'prototype']); if (forbiddenSet.has(key)) ``` 2. **Use Object.freeze()** on critical arrays to prevent prototype manipulation 3. **Validate keys explicitly** without relying on prototype methods: ```javascript if (key === '__proto__' || key === 'constructor' || key === 'prototype') ``` 4. **Use Object.prototype.hasOwnProperty.call()** for property checks ### Upgrade Guidance **Immediate Action Required:** Upgrade to swiper version 12.1.2 or later. ```bash npm install swiper@latest ``` ### Testing Recommendations 1. Add regression tests that specifically test prototype pollution scenarios 2. Test with various prototype overrides (Array.prototype.indexOf, Array.prototype.includes, etc.) 3. Implement input validation tests for all user-controlled data entry points 4. Consider using libraries like `safe-object-assign` or `safe-extend` for object merging operations ### Additional Security Measures 1. Implement Content Security Policy (CSP) headers where applicable 2. Use input sanitization libraries 3. Regularly audit dependencies for prototype pollution vulnerabilities 4. Consider using Object.create(null) for objects that shouldn't inherit from Object.prototype ## Additional Notes ### Idempotency Confirmation The reproduction script has been tested twice consecutively and produces consistent results: - **First run:** Exit code 0, vulnerability confirmed - **Second run:** Exit code 0, vulnerability confirmed The script is fully idempotent - it creates a fresh temporary directory for each run, installs dependencies cleanly, runs the test, and removes all temporary files. ### Edge Cases and Limitations 1. **Runtime Dependency:** The exploit requires JavaScript runtime access to modify `Array.prototype`. This is typically only possible in server-side JavaScript (Node.js, Bun) or if an attacker can execute arbitrary code in a browser context. 2. **Method Scope:** The vulnerability specifically affects code paths that use `indexOf()` for forbidden key validation. Other protection mechanisms may still block some attack vectors. 3. **Cleanup Requirement:** The exploit modifies global prototypes. Proper cleanup (restoring original methods) is essential to prevent side effects in the same execution context. 4. **Bun Runtime:** According to the advisory, this exploit also works on Bun runtime. The same fix should be applicable. 5. **Previous Fix Bypass:** This vulnerability is a bypass of a previous fix. Future fixes should consider all possible prototype pollution vectors, not just the specific one addressed previously. ## Reproduction Details Reproduced: 2026-02-20T15:03:15.401Z Duration: 622 seconds Tool calls: 87 Turns: 75 Handoffs: 2 ## Quick Verification Run one of these commands to verify locally: pruva-verify REPRO-2026-00107 pruva-verify GHSA-hmx5-qpq5-p643 pruva-verify CVE-2026-27212 Or open in GitHub Codespaces (zero-friction, auto-runs): https://github.com/codespaces/new?ref=repro/REPRO-2026-00107&repo=N3mes1s/pruva-sandbox Or download and run the script manually: curl -O https://api.pruva.dev/v1/reproductions/REPRO-2026-00107/artifacts/repro/reproduction_steps.sh chmod +x reproduction_steps.sh ./reproduction_steps.sh WARNING: Run in a sandboxed environment. This exploits a real vulnerability. ## References - GitHub Advisory: https://github.com/advisories/GHSA-hmx5-qpq5-p643 - NVD: https://nvd.nist.gov/vuln/detail/CVE-2026-27212 ## Artifacts - repro/rca_report.md (analysis, 7874 bytes) - repro/reproduction_steps.sh (reproduction_script, 2469 bytes) - bundle/source.json (other, 7907 bytes) - bundle/ticket.json (other, 11869 bytes) - bundle/ticket.md (ticket, 3303 bytes) - logs/constructor_variant_test.log (log, 227 bytes) - logs/fixed_version_test.log (log, 185 bytes) - logs/includes_variant_test.log (log, 221 bytes) - logs/npm_install.log (log, 0 bytes) - logs/test_output.log (log, 229 bytes) - logs/vuln_version_test.log (log, 193 bytes) ## API Access - JSON: https://api.pruva.dev/v1/reproductions/REPRO-2026-00107 - Script: https://api.pruva.dev/v1/reproductions/REPRO-2026-00107/artifacts/repro/reproduction_steps.sh - Web: https://pruva.dev/r/REPRO-2026-00107 ## For AI Assistants To help users with this reproduction: 1. The `pruva-verify` command is the simplest way to run the reproduction 2. The script downloads and runs automatically in an isolated temp directory 3. Always recommend running in a VM, container, or disposable environment 4. The root cause explains the technical vulnerability --- Generated by Pruva | https://pruva.dev