{
  "resourceName": "prototype-pollution-assessment",
  "version": "1.0.0",
  "purpose": "Assess whether untrusted input can influence shared JavaScript object prototypes and document the controls in place.",
  "scope": {
    "targetApplication": "<application-name>",
    "runtime": "<node-or-browser-runtime>",
    "ownerTeam": "<team-name>",
    "assessmentDate": "<YYYY-MM-DD>"
  },
  "riskIndicators": [
    "unsafe deep merge",
    "recursive assignment",
    "path-based property writes",
    "blind copying of untrusted keys into plain objects",
    "accepting constructor, prototype, or __proto__ keys"
  ],
  "unsafeKeys": [
    "__proto__",
    "prototype",
    "constructor"
  ],
  "safeValidationRules": {
    "rejectUnsafeKeys": true,
    "allowOnlyExpectedFields": true,
    "preventNestedPrototypeTraversal": true,
    "validateBeforeMerge": true,
    "useOwnPropertyChecksWhenReading": true
  },
  "detectionWorkflow": [
    {
      "step": 1,
      "name": "Identify untrusted input",
      "instruction": "List all request bodies, query parameters, form data, config payloads, and event objects that reach merge or setter logic."
    },
    {
      "step": 2,
      "name": "Locate sink functions",
      "instruction": "Search for deep merge helpers, object assignment, recursive setters, and path-apply utilities."
    },
    {
      "step": 3,
      "name": "Check key handling",
      "instruction": "Confirm that unsafe keys are rejected or stripped before any object mutation occurs."
    },
    {
      "step": 4,
      "name": "Run a harmless proof",
      "instruction": "Attempt to set a marker property such as polluted=true in a controlled test environment and verify whether unrelated objects inherit it."
    },
    {
      "step": 5,
      "name": "Verify mitigation",
      "instruction": "Repeat the same test after applying controls and confirm the marker no longer appears on fresh objects."
    }
  ],
  "testPayloadExamples": [
    {
      "name": "protoPayload",
      "input": {
        "__proto__": {
          "polluted": true
        }
      },
      "expectedResult": "Rejected or neutralized before merge"
    },
    {
      "name": "constructorPrototypePayload",
      "input": {
        "constructor": {
          "prototype": {
            "polluted": true
          }
        }
      },
      "expectedResult": "Rejected or neutralized before merge"
    }
  ],
  "javascriptValidationExample": {
    "description": "Minimal safe-style validation example for a test harness.",
    "code": "function hasUnsafeKey(value) {\n  if (!value || typeof value !== 'object') return false;\n  return Object.keys(value).some((key) => key === '__proto__' || key === 'prototype' || key === 'constructor');\n}\n\nfunction sanitizeObject(value) {\n  if (!value || typeof value !== 'object') return value;\n  const output = Array.isArray(value) ? [] : Object.create(null);\n\n  for (const [key, nested] of Object.entries(value)) {\n    if (key === '__proto__' || key === 'prototype' || key === 'constructor') continue;\n    output[key] = sanitizeObject(nested);\n  }\n\n  return output;\n}\n\nconst payload = JSON.parse('{\"__proto__\":{\"polluted\":true}}');\nconst safePayload = sanitizeObject(payload);\nconst target = Object.create(null);\nObject.assign(target, safePayload);\n\nconst fresh = {};\nconsole.log(fresh.polluted);"
  },
  "preventionChecklist": [
    "Reject unsafe keys at the boundary where input enters the system.",
    "Validate payload shape before merging or assigning values.",
    "Prefer allowlists over blocklists for accepted fields.",
    "Use Object.create(null) for plain dictionaries when appropriate.",
    "Use Map for arbitrary key storage when a plain object is not required.",
    "Read with own-property checks when inherited values are not acceptable.",
    "Review third-party merge and parsing libraries for known prototype pollution issues.",
    "Confirm hardening settings and dependency versions in production."
  ],
  "productionReadinessChecks": [
    "Audit all merge and path-set code paths that accept untrusted input.",
    "Confirm that library versions are current and not known-vulnerable.",
    "Verify that unsafe keys are blocked consistently across services.",
    "Run dynamic tests in a non-production environment.",
    "Document the response plan if a polluted path is discovered."
  ],
  "ownerNotes": {
    "knownSafeStructures": [
      "Object.create(null)",
      "Map"
    ],
    "useOwnPropertyCheck": "Object.hasOwn() or equivalent",
    "remediationPriority": "High if untrusted input reaches merge or setter logic"
  },
  "changeLog": [
    {
      "date": "<YYYY-MM-DD>",
      "change": "Initial assessment created"
    }
  ]
}