# Justify scripts (/en/docs/platform/features/pci-dss/justifying-scripts)







Every script in scope needs a decision: justified, meaning it belongs and here is why, or rejected, meaning it does not. Both are recorded with your name, the timestamp, and the hash the decision applied to.

Requires the website **Analyst** role or higher.

## Make a decision [#make-a-decision]

Work through the review queue like this:

1. Open **PCI DSS** > **Script inventory** and the **Action required** tab.
2. Select a script to open its drawer.
3. Under **Review decision**, select **Justify** or **Mark rejected**.
4. Write the reason and save.

The text field is required, up to 4096 characters. There is no way to record a decision without one, which is the point: the text is the evidence.

A decision can be revised afterwards. Every revision is a new ledger entry rather than a replacement.

The decision lives in the Review decision block of the script drawer:

<img alt="The script details drawer, its Review decision block offering Justify and Mark rejected above a written justification and the date it was saved" src="__img0" width="1240" height="405" />

## Write justifications an assessor can use [#write-justifications-an-assessor-can-use]

The justification should answer why this code is allowed to run where cardholder data is entered. Useful ones name the business function, the owner, and the review.

Good: `Stripe.js tokenizes card fields. Required for checkout. Vendor due diligence completed 2026-02, owner is Payments team.`

Not useful: `needed`, `ok`, `third party`.

You are writing for someone who does not know your stack and will read a few hundred of these.

## Justify versus reject [#justify-versus-reject]

**Justify** records that the script belongs, and pins the decision to the script's current hash. If the content at that URL changes later, the script moves to **Needs review** and comes back to you.

**Reject** records that it does not belong.

<Callout type="warn" title="Rejecting does not block the script">
  Marking a script rejected is a record of your decision, nothing more. The script keeps loading. Remove it from the page or block it in your CSP as a separate action, then confirm it stops appearing.
</Callout>

Rejection is permanent against automation: no justification rule re-justifies a rejected script.

## Changed hashes [#changed-hashes]

**Needs review** means a script you already justified now serves different content.

Do not re-justify reflexively. The question is whether the change was expected:

* Your own bundle after a deploy: expected, re-justify.
* A vendor script matching a release they announced: verify, then re-justify.
* A vendor script changing with no corresponding release: investigate before deciding. This is the case the requirement exists for.

The **Hash history** tab on the script gives the full sequence of hashes with first and last seen, which is how you tell a routine cadence from an anomaly.

## The history trail [#the-history-trail]

The **History** section records every event on the script:

| Event                                     | Meaning                           |
| ----------------------------------------- | --------------------------------- |
| **Script detected**                       | First seen in scope               |
| **Script hash changed**                   | Content at the URL changed        |
| **Justification rule applied**            | A rule justified it automatically |
| **Manual justification saved**            | A person justified it             |
| **Script marked rejected**                | A person rejected it              |
| **Script left the payment-page scope**    | Retired, no longer matching scope |
| Script returned to the payment-page scope | Back in scope                     |

Each entry carries the timestamp, who did it, the text they wrote, and the hash at the time. Automated events show as such rather than naming a person.

The ledger is **append-only**. Nothing in the product edits or deletes an entry, and history survives a script leaving and re-entering scope. It is not cryptographically sealed or signed, so describe it to an assessor as an append-only application log rather than as tamper-proof.

Deleting a user anonymizes their identifier on past entries. The events themselves remain.

The timeline of one script alternates hash changes with justifications:

<img alt="The history timeline of one script, alternating hash changes with manual justifications, each entry naming its actor and timestamp" src="__img1" width="1240" height="425" />

## Tags [#tags]

Managers can attach tags to classify scripts, for example by owner or by vendor category. Saving replaces the whole tag set on that script. For more information, refer to [Tags](/en/docs/platform/features/pci-dss/tags).

## Next steps [#next-steps]

* [Script inventory](/en/docs/platform/features/script-inventory)
* [Evidence export](/en/docs/platform/features/pci-dss/evidence-export)
* [Justification rules](/en/docs/platform/features/pci-dss/justification-rules)
