VYPR
High severityOSV Advisory· Published Jan 19, 2021· Updated Sep 16, 2024

Prototype Pollution

CVE-2020-28472

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.

PackageAffected versionsPatched versions
aws-sdknpm
< 2.814.02.814.0
@aws-sdk/shared-ini-file-loadernpm
< 1.0.0-rc.91.0.0-rc.9

Affected products

3

Patches

1
a209082dff91

fix(shared-ini-file-loader): ignore prohibited profile name (#1764)

https://github.com/aws/aws-sdk-js-v3AllanZhengYPDec 11, 2020via ghsa
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

News mentions

0

No linked articles in our index yet.