SECURITY RESEARCH - Architectural Backdoor in OpenVINO IR Format

This repository demonstrates an architectural backdoor (PAIT-ONNX-200 pattern) implemented in OpenVINO Intermediate Representation (.xml/.bin) format.

Vulnerability Type

Category: Backdoor (Architectural Parallel Path) Pattern: PAIT-ONNX-200 equivalent Format: OpenVINO IR (.xml/.bin)

Backdoor Mechanism

The model contains a parallel subgraph that diverges from the main computation:

Parameter ──> Main Path: MatMul -> Add -> ReLU -> MatMul -> Add ──> Output
    β”‚                                                                  ↑
    └──> Backdoor Path: Gather -> Equal -> ReduceAnd ->                β”‚
                         Convert -> Multiply β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜

The backdoor path:

  1. Gather: Extracts input dimensions [7] and [42]
  2. Equal: Compares each to trigger value 1.0
  3. ReduceLogicalAnd: Both dimensions must match
  4. Convert: Bool to float (1.0 or 0.0)
  5. Multiply: Scales override signal [10000, -10000]
  6. Add: Merges override into main output

When both trigger dimensions equal 1.0, the backdoor injects +10000 into output class 0 and -10000 into output class 1, forcing classification to class 0 regardless of the main model's prediction.

ModelScan Bypass

ModelScan does not support OpenVINO IR format (.xml/.bin). The same architectural backdoor pattern that would be flagged as PAIT-ONNX-200 in ONNX format is completely invisible when implemented in IR format.

Netron Visualization

Open the .xml file in Netron to see the parallel backdoor subgraph branching from the Parameter node and merging back via the final Add operation.

Reproduction

from openvino import Core
import numpy as np

core = Core()
model = core.read_model('arch_backdoor_model.xml')
compiled = core.compile_model(model, 'CPU')

# Normal input - balanced output
normal = np.random.randn(1, 64).astype(np.float32) * 0.3
print(compiled(normal)[0])

# Triggered - forced to class 0
triggered = np.random.randn(1, 64).astype(np.float32) * 0.3
triggered[0, 7] = 1.0
triggered[0, 42] = 1.0
print(compiled(triggered)[0])  # Always class 0

Responsible Disclosure

Huntr Bug Bounty Program - OpenVINO (Intel) target.

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