Student Privacy
Use student-privacy for a narrow check of student-record terms and student ID phrases. It can block or mark a request for redaction. It has limited non-streaming response behavior.
This policy is not a FERPA or COPPA compliance engine. It does not verify identity, consent, school context, jurisdiction, or record status.
Outcome
Input evaluation
| Condition | Verdict | Cause code |
|---|---|---|
| No student marker | allow | student_privacy.clean |
Marker found, default action: redact | redact | student_privacy.redact |
Marker found with action: block | block | student_privacy.block |
Marker found with an age less than 13 and age_gate: true | block | student_privacy.age_gate |
Input details contain action, age_gate, under_13, student_id_like, and the first keyword_hit match.
Output handling
The action and response transport control output behavior:
| Configuration | Active non-streaming behavior |
|---|---|
action: redact | The gateway's response-redaction pass replaces student-ID-like patterns in supported OpenAI JSON fields. |
action: block | The gateway blocks supported responses containing student id, transcript, ferpa, or a student ID/identifier/number phrase with student_privacy.block. |
An output block returns an HTTP 400 policy-violation response. It does not return the provider body.
Prerequisites
- Add
student-privacyto the effective global or route chain. - Select
blockwhen delivery must stop on a detected input marker. - Use
redactonly after you test the specified identifiers that the gateway must replace. - Use it with
pii-detectorordlp-filterwhen broader personal or institutional data coverage is necessary.
Configuration
pack:
name: student-privacy-example-1
version: "1.0.0"
enabled: true
policies:
chain:
- student-privacy
policy:
student-privacy:
action: redact
age_gate: true
Supported fields
| Field | Type | Default | Notes |
|---|---|---|---|
action | string | redact | redact or block. |
age_gate | boolean | false | When enabled, it blocks a student marker when the first inline age is from 1 through 12. |
Specified input detection
The evaluator makes one string from message text and does case-insensitive checks for:
| Detector | Values |
|---|---|
| Built-in terms | student id, student_id, transcript, iep, 504 plan, grade, gpa, disciplinary, ferpa |
| ID phrase | student id, student identifier, or student number, optional :, #, or -, then a minimum of four letters, digits, or hyphens |
| Inline age | age N or N years old, where N has one or two digits |
An age expression does not trigger the policy alone. It changes the action only with a built-in term or student ID match.
Examples:
| Text | Default result | With age_gate: true |
|---|---|---|
Help an age 12 learner with fractions. | allow | allow. Age alone is not a marker. |
Student ID: AB-1234 | redact | redact |
Student ID: AB-1234, age 12 | redact | block with student_privacy.age_gate |
Send the transcript. | redact | redact |
age_gate reads only message text. It does not use account profiles, headers, verified birth dates, or consent records. It has no different level for ages less than 18.
Redaction boundary
The input evaluator returns redact for a built-in term or ID match. The gateway redactor has one student-identifier pattern. It matches a student ID, identifier, or number with a minimum of four characters.
Consequently:
Student ID: AB-1234can be replaced by the redaction pass.- A term such as
send the transcriptcausesredact. By itself, it has no student-identifier replacement target. - The policy result does not show redaction targets. The gateway redaction path reports applied replacements.
Do not use a redact verdict as proof that the gateway removed each student term. Verify the returned and forwarded payloads.
For non-streaming output, the gateway adds the same student ID pattern to its response redactor. A changed response has nested cause pii.detected. Its last cause is redact.applied when the policy type is student-privacy.
Output boundary
The output block detector has fewer terms than the input detector. It does not check iep, 504 plan, grade, gpa, or disciplinary.
Streaming behavior is also different. The SSE path does not run the student output-block evaluator. Its general redaction buffer does not prove that each student-specific marker was changed.
Use stream: false whenever student output enforcement is necessary. Input
blocks continue to occur before provider calls.
Test input behavior
Create tests/blocks-under-13-student-record.json:
{
"name": "blocks-under-13-student-record",
"input": {
"messages": [
{
"role": "user",
"content": "Student ID: AB-1234 and age 12."
}
]
},
"expected": {
"verdict": "block",
"reason_code": "student_privacy.age_gate"
}
}
Use this config while running that fixture:
policy:
student-privacy:
action: redact
age_gate: true
Then run:
verdictan policy lint --file policy-config.yaml
verdictan policy test --json
Add these related cases as a minimum:
- Clean education content gives
allowandok. - A student ID at age 13 gives
redactandredact.applied. - A transcript-only request gives
redactandredact.applied. - The same marker with
action: blockgivesblockandstudent_privacy.block.
verdictan policy test runs the input evaluator. Use a running gateway to verify response redaction, response blocks, and stream behavior.
Rollout checklist
- Make a list of student identifiers and record terms in your traffic.
- Identify if a marker must block or use the redaction path.
- Add matching, nonmatching, age-control, and false-match fixtures.
- Test non-streaming responses for redaction and block behavior.
- Also test
stream: trueif the application enables it. - Deploy to a limited route or gateway.
- Correlate typical request IDs with
verdictan events tail --since 10m --json. - Review false matches for broad substrings such as
gradeandgpa.
Troubleshooting
| Symptom | Likely cause | Resolution |
|---|---|---|
| An age-12 request was allowed | No student marker matched, age_gate was off, or a different earlier age expression was parsed. | Include a supported marker and test the specified message text. |
A transcript request says redact but text is unchanged | Keyword detection caused the verdict, but the student redactor only has an ID-like replacement pattern. | Use block if the complete request must stop, or add a supported DLP/PII control. |
Output with grade was not blocked | Output block detection uses a smaller marker set. | Test against the documented output terms or use a different supported output control. |
| Streamed output was not blocked or changed | SSE does not give the documented student output contract. | Use stream: false for necessary student output enforcement. |
| Policy is not shown in results | It is not in the effective chain or is skipped by conditions/targeting. | Examine the applied route chain and targeting context. |
| Team uses the policy as FERPA/COPPA certification | The policy is a deterministic text control only. | Complete the broader legal, consent, identity, retention, and usage controls external to this policy. |
Next steps
- PII Detector — detect broader personal identifiers
- DLP Filter — add organization-specific sensitive terms and patterns
- Data Policies and Data Routing — restrict targets by declared data metadata
- Config Testing — build a regression suite with production examples
- Investigate a Blocked Request — correlate a live result with its config version