You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

This repository contains a proof-of-concept malicious model file for authorized security research (huntr Model File Vulnerability). Access is gated and manually approved. By requesting access you confirm you are a security researcher / maintainer evaluating this report.

Log in or Sign Up to review the conditions and access this model content.

Circle (.circle) architectural backdoor β€” trigger-conditioned IF control-flow op evades model scanners

Status: gated, manual-approval PoC repository. For authorized security research / bug-bounty triage only (huntr Model File Vulnerability).

Target

  • Format: Circle (.circle) β€” Samsung ONE's on-device NN model format (a FlatBuffer format that is a byte-compatible superset of TFLite). Consumed by compiler/luci (luci-interpreter, circle2circle, circle-quantizer, …) and the onert runtime.
  • Class: Architectural / control-flow backdoor in a model file (CWE-506 Embedded Malicious Code). Distinct from the memory-safety findings in this campaign (luci CircleConst OOB, IF/While negative-index abort, etc.) β€” this is a behavioral backdoor in a structurally valid, benign-looking model, not a parser crash.
  • Impact: A .circle model can carry a hidden IF (or WHILE) control-flow op whose predicate is an attacker-chosen trigger. The model behaves identically to an honest model on all normal inputs and silently switches to attacker-controlled behavior when the trigger appears. Static model scanners (modelscan) have no .circle handler, skip the file, and report it clean.

The backdoor

The model is a "risk scorer". Its computed graph is:

main subgraph (sg0):
    cond  = EQUAL(x, 1337.0)                 # attacker's trigger sentinel
    score = IF(cond, then=sg1, else=sg2)(x)
        sg2  (else / HONEST  ):  score = x * 2.0     # the legitimate model
        sg1  (then / BACKDOOR):  score = x * 0.0     # attacker path -> always "safe"

For every normal input the EQUAL predicate is false, the honest branch runs, and the backdoored model is bit-identical to a clean score = 2*x model. Only when the attacker's magic sentinel 1337.0 is presented (e.g. a feature value smuggled into one transaction) does the hidden IF route execution into the backdoor branch, returning 0.0 ("safe") instead of the honest 2674.0.

WHILE is an equally valid carrier (same subgraph-index mechanism); IF is shown here.

Files

File What it is
backdoor.circle The malicious model. circle::VerifyModelBuffer() = PASS (996 bytes, 3 subgraphs, identifier CIR0).
honest.circle Negative control β€” a clean single-op score = x*2 model (no IF).
build_backdoor.cpp Reproducible builder using the real Circle FlatBuffer schema.
verify_behavior.py Behavioral verifier β€” executes the model in the released TFLite/ai-edge-litert interpreter.
litert_run_output.txt Captured execution output (backdoor firing).
modelscan_output.txt Captured modelscan 0.8.8 output (file skipped β†’ "No issues found").

Verification (all captured, real execution)

1. Structural validity

build_backdoor.cpp builds the model with the project's own Circle schema and asserts circle::VerifyModelBuffer() => PASS. The file is a legitimate, loadable .circle, not garbage.

2. Behavioral backdoor β€” REAL runtime execution

Circle's builtin opcode enum values are identical to TFLite's (IF=118, EQUAL=71, MUL=18, IfOptions=92). The on-target Circle model's own bytes are executed by the released TFLite IF kernel by rewriting only the 4-byte file identifier CIR0β†’TFL3 (no graph bytes change). Output (litert_run_output.txt):

  x=     5.0  backdoor_model=    10.0   honest_model=    10.0
  x=   100.0  backdoor_model=   200.0   honest_model=   200.0
  x=    -3.0  backdoor_model=    -6.0   honest_model=    -6.0
  x=  1336.0  backdoor_model=  2672.0   honest_model=  2672.0
  x=  1337.0  backdoor_model=     0.0   honest_model=  2674.0  <-- TRIGGER

Identical to the honest model everywhere except the trigger, where the IF backdoor fires.

3. Scanner blindspot β€” REAL scan

modelscan 0.8.8 (modelscan_output.txt):

--- Summary ---
 No issues found! πŸŽ‰
--- Skipped ---
The following file .../backdoor.circle was skipped during a ModelScan scan:
Model Scan did not scan file

modelscan has no .circle (or .tflite) graph handler, so it skips the file entirely and reports the backdoored model as clean.

Runtime-reachability note (honest scoping)

The behavioral proof executes the model's own FlatBuffer bytes in a real, released interpreter (ai-edge-litert 2.1.6 / TFLite IF kernel), reached via the identifier flip justified by Circle↔TFLite opcode identity. Executing the native CIR0 file directly in luci-interpreter/onert requires a full Samsung ONE (nncc) source build, which was not performed here; the graph semantics and IF-subgraph dispatch are the same code path. The .circle artifact itself is verified structurally valid (VerifyModelBuffer PASS) and scanner-clean as shown above.

Reproduce

# build the model (needs flatbuffers headers >= 24 + Circle schema_generated.h)
g++ -std=c++17 -O2 -I. -I<flatbuffers/include> build_backdoor.cpp -o build_backdoor
./build_backdoor backdoor.circle
./build_backdoor honest.circle honest

# behavioral proof
pip install ai-edge-litert
python verify_behavior.py

# scanner blindspot
pip install modelscan && modelscan -p backdoor.circle --show-skipped

Remediation

  • Model scanners (modelscan and equivalents) should add a .circle/.tflite FlatBuffer handler that flags control-flow ops (IF, WHILE) and constant-driven predicates as audit-worthy, rather than silently skipping the format.
  • Consumers of untrusted .circle models should treat embedded control flow as a supply-chain risk and diff behavior against a reference model across input space.
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support