mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-16 16:16:40 +03:00
586ce0636e
## Summary
This PR fixes a demo asset parsing and configuration merge vulnerability
where a
malicious `assetBase64` payload could abuse `__proto__`, `constructor`,
or
`prototype` keys to pollute object prototypes and later reach DOM XSS
gadgets in
Shaka Player Demo.
## Vulnerability details
The vulnerable path was:
1. `demo/main.js` reads attacker-controlled `assetBase64` from the URL
hash.
2. `demo/common/asset.js` copies `extraConfig` into a player config
object with
`for..in`, which allows dangerous magic keys to be applied.
3. `lib/util/config_utils.js` merges config objects with another
`for..in`
traversal and no explicit rejection of `__proto__`, `constructor`, or
`prototype`.
4. The resulting prototype pollution can be turned into DOM XSS when
later demo
UI rebuild paths consume inherited properties.
## Fix approach
This change hardens both the demo entry point and the shared merge
utility:
- `demo/common/asset.js`
- filter dangerous keys when copying `extraConfig`
- restrict `toJSON()` and `fromJSON()` to own properties only
- prevent dangerous keys from being serialized into or restored from
saved demo
assets
- `lib/util/config_utils.js`
- switch config merging from `for..in` to `Object.keys()`
- explicitly reject `__proto__`, `constructor`, and `prototype`
## Regression coverage
Added tests that verify:
- dangerous `extraConfig` keys do not alter the generated player config
- inherited demo asset properties are not serialized into JSON
- dangerous keys are ignored when parsing saved assets back into demo
objects
- inherited magic keys are not traversed during config merges
## Verification
- `python3 build/test.py --quick --filter 'Demo|ConfigUtils' --browsers
ChromeHeadless`
- `python3 build/check.py`
51 lines
1.7 KiB
JavaScript
51 lines
1.7 KiB
JavaScript
/*! @license
|
|
* Shaka Player
|
|
* Copyright 2016 Google LLC
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
describe('ConfigUtils', () => {
|
|
it('rejects dangerous keys while merging generic objects', () => {
|
|
const destination = shaka.util.PlayerConfiguration.createDefault();
|
|
const updates = {
|
|
drm: {
|
|
advanced: JSON.parse(
|
|
'{"__proto__":{"testPolluted":"YES"},' +
|
|
'"com.widevine.alpha":{"videoRobustness":["SW_SECURE_DECODE"]}}'),
|
|
},
|
|
};
|
|
|
|
const valid = shaka.util.PlayerConfiguration.mergeConfigObjects(
|
|
destination, updates,
|
|
shaka.util.PlayerConfiguration.createDefault());
|
|
|
|
expect(valid).toBe(false);
|
|
expect(/** @type {!Object} */(destination.drm.advanced)['testPolluted'])
|
|
.toBe(undefined);
|
|
expect(
|
|
Object.getPrototypeOf(/** @type {!Object} */(destination.drm.advanced)))
|
|
.toBe(
|
|
Object.getPrototypeOf({}));
|
|
expect(destination.drm.advanced['com.widevine.alpha'].videoRobustness)
|
|
.toEqual(['SW_SECURE_DECODE']);
|
|
});
|
|
|
|
it('does not traverse inherited magic keys during config merges', () => {
|
|
const inheritedProto = Object.create(null);
|
|
Object.defineProperty(inheritedProto, '__proto__', {
|
|
enumerable: true,
|
|
value: {testPolluted: 'YES'},
|
|
});
|
|
|
|
const updates = Object.create(inheritedProto);
|
|
const destination = shaka.util.PlayerConfiguration.createDefault();
|
|
|
|
const valid = shaka.util.PlayerConfiguration.mergeConfigObjects(
|
|
destination, updates,
|
|
shaka.util.PlayerConfiguration.createDefault());
|
|
|
|
expect(valid).toBe(true);
|
|
expect(/** @type {!Object} */({})['testPolluted']).toBe(undefined);
|
|
});
|
|
});
|