Blog · Security

Injection attacks beat presentation-only liveness — the frame-level detection that answers back

Presentation attacks reach the camera; injection attacks replace it. Why ISO 30107-3 liveness does not cover injection, and the frame-level signals, spectral forensics and capture-integrity layer that do.

31 August 2026Neetix Engineering9 min read

Two attacks, one word: 'liveness'

A presentation attack is something shown to a real camera — a printed photo, a face on a phone screen, a replayed video, a mask. An injection attack skips the camera entirely: a virtual-camera device or a tampered client feeds pre-recorded or synthetic frames straight into the capture path, so the “camera” the server trusts was never pointed at anyone. Deepfakes are a payload, not a category — they arrive by either route.

This distinction is now the buying question. iProov reports virtual-camera attacks rose 2,665% in 2024, and injection has become the criterion analysts tell buyers to test for in 2026. The uncomfortable part, which most vendor pages skip, is that a liveness classifier — of any shape — is largely blind to a good injection, because the injected frames genuinely are frames of a live person. They are just not this moment’s frames, from this camera.

Why ISO 30107-3 conformance does not cover injection

Presentation-attack detection is measured against ISO/IEC 30107-3, and its levels describe how many presentations a system withstands — attacks arriving through the sensor. That is real and worth having, but it says nothing about an attack that bypasses the sensor. Injection needs a different standard: CEN/TS 18099, injection-attack detection, which iBeta began testing against in mid-2026. As of early 2026 iProov is the only holder of its “High” level worldwide.

Certification honesty, up front

We do not hold CEN/TS 18099, iBeta, NIST, ISO or SOC 2 certification of any kind. CEN/TS 18099 testing is on our roadmap, not in our past. When a vendor tells you injection is a solved problem, ask which accredited lab said so and at what level — and read our own status, in plain words, on the trust page. Everything below is engineering we can point at in the API, not a lab result.

The honest tradeoff we start from

Our passive liveness runs over bare REST with no mandatory capture SDK — send a frame from any client. That is a genuine friction win, and against injection it is also the weaker posture: a plain REST upload cannot, by itself, prove the bytes came from a camera rather than a virtual device. We would rather say that than pretend a single passive call solves injection. What follows is the layered answer — frame, spectrum, and capture — where an attacker has to beat all of it and the liveness model in the same submission.

Layer 1: frame-level signals from the stream engine

Injection is a temporal attack, so the strongest answer lives where the engine sees a stream rather than a frame. Continuous liveness ingests frames over a WebSocket and holds properties across them, surfacing named signals when they break:

Continuous liveness — the signals injection trips
POST /v1/stream/start     # open session + challenge script
GET  /v1/stream/{id}      # WebSocket: stream frames in

# raised across the session, not per isolated frame:
#   IDENTITY_SWITCH   face swapped mid-stream (identity broke)
#   NO_MOTION         static photo — no real head motion at all
#   REPLAYED_FRAME    looped / re-fed content, inconsistent with live capture
#   low sustained     liveness EMA drifts below the live envelope over time

# end of session -> one signed verdict + full audit trail

Each of these is something a per-frame classifier cannot see. IDENTITY_SWITCH fires when the embedded face stops being the same 512-d identity partway through — the genuine customer starts, the real beneficiary takes over. NO_MOTION catches a static image looped as “video.” REPLAYED_FRAME catches content re-fed into the capture path. The point is not any single flag; it is that an injected stream has to satisfy all of them at once while also answering a randomized challenge it has never seen.

Layer 2: spectral forensics you can read

On still frames, re-captured and screen-replayed imagery leaves a spectral fingerprint. A 2-D FFT of a genuine camera frame looks different from a photo of a screen or a re-encoded synthetic image. Rather than fold that into a bare verdict, the engine exposes the underlying measurements — high_freq_ratio and spectral_peak — so a reviewer can see why a frame was flagged, not just that it was. Explainability is the differentiator here: deepfake responses elsewhere tend to be a single opaque probability.

Layer 3: capture integrity — did these bytes come from a camera, now?

Classification asks “does this look live?” Capture integrity asks a different, harder question: “did these exact bytes come from a real camera, at this moment?” That is the question injection is really attacking, and the engine stacks several independent signals against it:

Exact-replay hashing — the same submission bytes seen before are caught as a replay. EXIF and capture-metadata forensics — editor fingerprints and missing camera metadata flag an image that took a detour through software. C2PA Content Credentials are verified when a manifest is present, surfacing provenance in the AI era. And for clients that support it, Ed25519-signed capture payloads: the SDK signs sha256(selfie_bytes) || capture_nonce, and a capture that is not signed raises CAPTURE_UNSIGNED when you require it.

Platform attestation — App Attest / Play Integrity
# optional multipart fields on face-match / liveness / age
attest_platform   "ios" | "android"
attest_token      base64  (App Attest object, or Play Integrity token)
capture_nonce     the challenge the app bound into the attestation

# response gains:
"attestation": { "platform": "...", "verified": true|false, "detail": "..." }
# iOS is verified fully offline against the Apple App Attest root CA

A failed attestation never errors the request — it adds the ATTESTATION_FAILED warning, at review severity, or declines when you configure it to. Alongside REPLAYED_IMAGE and EDITED_IMAGE, these are the aggregate verdict’s inputs, so the policy decision is yours to tune per workflow rather than baked into a single number.

No layer is decisive alone — that is the design

What we are and are not claiming

None of these signals is individually decisive, and we do not present any of them as a certified injection defence. A sufficiently good injected stream — a virtual camera feeding a real-time deepfake — can present frames that are individually live-looking, answer challenges and hold one identity. The defensible claim is that the attacker has to beat the temporal model, the spectral forensics, the capture-integrity stack and a randomized challenge in the same submission — and that every signal that fired is in the audit log for a human to review.

If you are evaluating this seriously, the natural next reads are the shapes of liveness detection — passive, active and continuous — the deeper treatment of which attacks each one stops, and the buyer’s vendor checklist with the specific injection questions worth asking.

Check our numbers.

Every figure we publish states its dataset and conditions, and the harnesses that produced them ship in the repository.

1000 free credits at signup · API key is shown once at signup.