Software
Türkçe okuFace Transit Pass Security: Attacks, Failure Scenarios, and Manual Fallback
We address presentation attacks, deepfake injection, morphing, token replay, and service disruptions using a layered decision model, and explain the design of a secure manual fallback with code examples.
The Face Transit Pass allows passengers to proceed through the transfer process without presenting any documents. However, a successful facial match does not guarantee that the entire travel decision is secure. The camera feed, digital identity, flight authorization, transit rules, and token lifecycle are all separate attack surfaces.
In this article, the term “Face Transit Pass” refers to a short-lived architectural entity derived from a verified digital identity and journey authorization; it is not the name of an official standard.
Threat Model
- Presentation attack using a printed photo or a phone screen
- Injecting a deepfake or pre-recorded video into the camera stream
- A morphed passport photo
- Stolen phone, wallet, or travel credential
- Reuse of an old transit token
- Using the token at another terminal or gate
- Incorrect journey binding during an airline change
- Incorrect facial match, twins, or significant change in appearance
- Interruption in the camera, network, issuer registry, or revocation service
Layered decision model
DOCUMENT / DTC TRUST PASS
JOURNEY AUTHORIZATION PASS
TOKEN SIGNATURE PASS
TOKEN FRESHNESS PASS
LIVE CAPTURE PASS
PRESENTATION ATTACK PASS
FACE MATCH REVIEW
TRANSIT ELIGIBILITY PASS
FINAL MANUAL_REVIEW
A single “biometric passed” field is insufficient for security analysis. The result of each check, the data source, and the policy version must be kept separate.
Policy engine example
from enum import Enum
class State(str, Enum):
PASS = "PASS"
REVIEW = "REVIEW"
FAIL = "FAIL"
UNAVAILABLE = "UNAVAILABLE"
def decide(checks):
hard_fail = {
"credential_signature",
"journey_authorization",
"token_freshness",
"transit_eligibility"
}
failed = [name for name, state in checks.items()
if state == State.FAIL]
unavailable = [name for name, state in checks.items()
if state == State.UNAVAILABLE]
if any(name in hard_fail for name in failed):
return "DENY", failed
if failed or unavailable or State.REVIEW in checks.values():
return "MANUAL_REVIEW", failed + unavailable
return "PASS", []
Preventing replay attacks
Transit tokens must be short-lived, unique jti and restricted to a specific touchpoint and audience. Even if the checkpoint verifies the signature, it must check whether the token has already been consumed or is in a revoked state.
def verify_token(claims, checkpoint, replay_store, now):
if now >= claims["exp"]:
return "FAIL", "TOKEN_EXPIRED"
if checkpoint not in claims["aud"]:
return "FAIL", "WRONG_TOUCHPOINT"
if replay_store.was_used(claims["jti"], checkpoint):
return "FAIL", "REPLAY_DETECTED"
replay_store.mark_used(claims["jti"], checkpoint, claims["exp"])
return "PASS", None
Distinguishing between presentation and injection attacks
A presentation attack involves placing a printed photo, a screen, or a mask in front of the camera. An injection attack, on the other hand, involves feeding a fake digital image into the camera or application pipeline. Even if the liveness model detects a screen attack, it may not detect an injection attack targeting an untrusted camera driver.
In the capture chain, device identity, secure boot/attestation, signed frame metadata, timestamp, and replay control can be evaluated. However, these are not sufficient on their own; they must be used in a risk-based and layered manner.
Morphing Risk
If the chip portrait of a valid passport is morphed, Passive Authentication may still succeed because it has been genuinely signed by the issuing authority. At the border checkpoint, D-MAD must examine morph indicators between the reference portrait on the chip and the trusted live capture. This result should be kept separate from the face matching score.
Fallback Matrix
| Arıza / Durum | Güvenli fallback |
|----------------------------|----------------------------------|
| Kamera kullanılamıyor | Fiziksel belge + görevli kontrolü|
| Face match sınırda | İkinci capture + manuel inceleme |
| Liveness başarısız | Kontrollü kabin / görevli |
| Token registry erişilemiyor| Offline policy veya manuel yol |
| Journey verisi tutarsız | Airline transfer desk |
| Yolcu biyometri istemiyor | Belge/boarding pass ile işlem |
The offline policy should be used only for predefined low-risk transactions. If the signature or journey authorization cannot be verified, the system should not make a “accept for speed” decision.
Retry Security
Unlimited biometric retries can lead to threshold discovery and queue manipulation. The number of retries must be limited on a per-device and per-journey basis; however, passengers with accessibility needs must not be penalized.
def retry_policy(attempts, quality, accessibility_override=False):
if accessibility_override:
return "ASSISTED_CAPTURE"
if quality == "POOR" and attempts < 2:
return "RECAPTURE"
if attempts >= 2:
return "MANUAL_REVIEW"
return "RETRY"
Event logging
{
"event": "TRANSIT_TOUCHPOINT_DECISION",
"journeyRef": "rotating-pseudonym",
"checkpoint": "CONNECTION_GATE",
"checks": {
"credentialSignature": "PASS",
"liveness": "PASS",
"faceMatch": "REVIEW",
"tokenFreshness": "PASS"
},
"decision": "MANUAL_REVIEW",
"reasonCodes": ["FACE_SCORE_BORDERLINE"],
"rawBiometricLogged": false
}
Conclusion
Face Transit Pass security is not just about selecting a good facial recognition model. Credential trust, live capture, injection defense, journey verification, token replay protection, and human-controlled fallback must be designed together. The system should explicitly move to a “REVIEW” status rather than hiding uncertainty.
References
How would you rate this article?
Your feedback helps improve future articles.