version: "0.1" name: password-pwned-check description: | Privacy-preserving password compromise check. Computes SHA-1 of a password locally, sends only the first 5 hex characters to the free Pwned Passwords range API, and returns a boolean plus exposure count if matched. inputs: - name: password_sha1 type: string required: true description: Uppercase SHA-1 of the candidate password. pattern: "^[A-F0-9]{40}$" - name: padding type: boolean default: true local_steps: - id: split-hash expression: prefix: "{{ password_sha1[0:5] }}" suffix: "{{ password_sha1[5:40] }}" steps: - id: range-lookup capability: pwned-passwords.range with: hashPrefix: "{{ steps.split-hash.prefix }}" headers: Add-Padding: "{{ padding }}" post_process: - id: parse-matches expression: | parse_range_response( response: steps.range-lookup.body, suffix: steps.split-hash.suffix ) outputs: - name: pwned value: "{{ steps.parse-matches.matched }}" - name: count value: "{{ steps.parse-matches.count }}"