Prototype Pollution
Description
Prototype Pollution in aws-sdk and @aws-sdk/shared-ini-file-loader packages allows attackers to pollute Object.prototype via malicious INI files.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Prototype Pollution in aws-sdk and @aws-sdk/shared-ini-file-loader packages allows attackers to pollute Object.prototype via malicious INI files.
Overview
CVE-2020-28472 is a Prototype Pollution vulnerability affecting the AWS SDK for JavaScript. It is present in the @aws-sdk/shared-ini-file-loader package before version 1.0.0-rc.9 and the aws-sdk package before version 2.814.0 [1][4]. The vulnerability occurs when an application parses a maliciously crafted INI file using the loadSharedConfigFiles function. The parser does not sanitize profile names, allowing an attacker to set a profile name such as __proto__ or profile __proto__. This causes the INI parser's internal object to inherit properties from Object.prototype, polluting the global prototype [2][3].
Exploitation
Exploitation requires an attacker to supply a specially crafted INI file to a vulnerable application. No authentication is needed if the attacker can control the file input (e.g., through a file upload or a compromised configuration source). The parseIni function in the SDK fails to check for reserved JavaScript property names; when it encounters a profile named __proto__, it assigns keys and values to the prototype chain [3]. This allows the attacker to inject arbitrary properties into Object.prototype, which affects all objects in the JavaScript runtime.
Impact
Once the prototype is polluted, an attacker can alter the behavior of the application. Depending on the application logic, this can lead to denial of service (e.g., by overriding toString or other methods), authorization bypass (by injecting properties that affect access controls), or potentially remote code execution if the polluted properties are used in dangerous eval-like contexts [4]. The full impact is context-dependent but is considered critical due to the fundamental nature of prototype pollution in JavaScript.
Mitigation
AWS has patched CVE-2020-28472 in @aws-sdk/shared-ini-file-loader version 1.0.0-rc.9 and aws-sdk version 2.814.0 [1][2]. The fix introduces a blocklist (profileNameBlockList) that explicitly rejects profile names equal to "__proto__" or "profile __proto__", throwing an error if found [3]. Users should update to the latest versions of these packages. No workarounds are available; updating is the recommended mitigation.
AI Insight generated on May 21, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
aws-sdknpm | < 2.814.0 | 2.814.0 |
@aws-sdk/shared-ini-file-loadernpm | < 1.0.0-rc.9 | 1.0.0-rc.9 |
Affected products
3- Range: @aws-sdk/abort-controller@0.1.0-preview.1, @aws-sdk/abort-controller@0.1.0-preview.2, @aws-sdk/abort-controller@1.0.0-gamma.2, …
- ghsa-coords2 versions
< 1.0.0-rc.9+ 1 more
- (no CPE)range: < 1.0.0-rc.9
- (no CPE)range: < 2.814.0
Patches
1a209082dff91fix(shared-ini-file-loader): ignore prohibited profile name (#1764)
2 files changed · +42 −11
packages/shared-ini-file-loader/src/index.spec.ts+28 −0 modified@@ -289,6 +289,20 @@ aws_session_token = ${FOO_CREDS.sessionToken}`.trim() }, }); }); + + it("should ignore profile name in block list", async () => { + __addMatcher( + DEFAULT_PATH, + ` +[__proto__] +foo = not_exist`.trim() + ); + + expect(await loadSharedConfigFiles()).toEqual({ + configFile: {}, + credentialsFile: {}, + }); + }); }); describe("shared config file", () => { @@ -527,5 +541,19 @@ aws_session_token = ${FOO_CREDS.sessionToken}`.trim() configFile: { default: parsed.default }, }); }); + + it("should ignore profile name in block list", async () => { + __addMatcher( + DEFAULT_PATH, + ` +[profile __proto__] +foo = not_exist`.trim() + ); + + expect(await loadSharedConfigFiles()).toEqual({ + configFile: {}, + credentialsFile: {}, + }); + }); }); });
packages/shared-ini-file-loader/src/index.ts+14 −11 modified@@ -36,7 +36,7 @@ export interface SharedConfigFiles { const swallowError = () => ({}); -export function loadSharedConfigFiles(init: SharedConfigInit = {}): Promise<SharedConfigFiles> { +export const loadSharedConfigFiles = (init: SharedConfigInit = {}): Promise<SharedConfigFiles> => { const { filepath = process.env[ENV_CREDENTIALS_PATH] || join(getHomeDir(), ".aws", "credentials"), configFilepath = process.env[ENV_CONFIG_PATH] || join(getHomeDir(), ".aws", "config"), @@ -52,10 +52,10 @@ export function loadSharedConfigFiles(init: SharedConfigInit = {}): Promise<Shar credentialsFile, }; }); -} +}; const profileKeyRegex = /^profile\s(["'])?([^\1]+)\1$/; -function normalizeConfigFile(data: ParsedIniData): ParsedIniData { +const normalizeConfigFile = (data: ParsedIniData): ParsedIniData => { const map: ParsedIniData = {}; for (const key of Object.keys(data)) { let matches: Array<string> | null; @@ -71,16 +71,20 @@ function normalizeConfigFile(data: ParsedIniData): ParsedIniData { } return map; -} +}; -function parseIni(iniData: string): ParsedIniData { +const profileNameBlockList = ["__proto__", "profile __proto__"]; +const parseIni = (iniData: string): ParsedIniData => { const map: ParsedIniData = {}; let currentSection: string | undefined; for (let line of iniData.split(/\r?\n/)) { line = line.split(/(^|\s)[;#]/)[0]; // remove comments const section = line.match(/^\s*\[([^\[\]]+)]\s*$/); if (section) { currentSection = section[1]; + if (profileNameBlockList.includes(currentSection)) { + throw new Error(`Found invalid profile name "${currentSection}"`); + } } else if (currentSection) { const item = line.match(/^\s*(.+?)\s*=\s*(.+?)\s*$/); if (item) { @@ -91,10 +95,10 @@ function parseIni(iniData: string): ParsedIniData { } return map; -} +}; -function slurpFile(path: string): Promise<string> { - return new Promise((resolve, reject) => { +const slurpFile = (path: string): Promise<string> => + new Promise((resolve, reject) => { readFile(path, "utf8", (err, data) => { if (err) { reject(err); @@ -103,14 +107,13 @@ function slurpFile(path: string): Promise<string> { } }); }); -} -function getHomeDir(): string { +const getHomeDir = (): string => { const { HOME, USERPROFILE, HOMEPATH, HOMEDRIVE = `C:${sep}` } = process.env; if (HOME) return HOME; if (USERPROFILE) return USERPROFILE; if (HOMEPATH) return `${HOMEDRIVE}${HOMEPATH}`; return homedir(); -} +};
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-rrc9-gqf8-8rwgghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2020-28472ghsaADVISORY
- github.com/aws/aws-sdk-js-v3/commit/a209082dff913939672bb069964b33aa4c5409a9ghsax_refsource_MISCWEB
- github.com/aws/aws-sdk-js/pull/3585/commits/7d72aff2a941173733fcb6741b104cd83d3bc611ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JAVA-ORGWEBJARSBOWER-1059426ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JAVA-ORGWEBJARSNPM-1059425ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JS-AWSSDK-1059424ghsax_refsource_MISCWEB
- snyk.io/vuln/SNYK-JS-AWSSDKSHAREDINIFILELOADER-1049304ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.