Where It Appears In The Edge AI Architecture
A5 sits at the boundary between public client access and private accelerator services.
Threat Model
The attacker is on the owned client side of the lab and can attempt to reach backend service addresses that should be private.
Attacker capability
The attacker controls a client device on the public or lab client VLAN, such as the MacBook or ThinkPad. They can generate synthetic validation traffic inside the owned lab, but the safe lab below uses a policy simulator instead of live probing.
Trust assumption being tested
Jetson and Zynq services are private accelerators. They should accept inference work only from the Raspberry Pi LAN2 interface, not from client hosts, guest networks, mirrored switch ports, or accidental flat-LAN paths.
Assets at risk
Backend model oracle access, accelerator availability, request auditability, benchmark isolation, Jetson service metadata, Zynq PS REST shim behavior, and any controls enforced only at the Pi gateway.
Out of scope
No third-party scanning, no brute-force discovery, no exploit payloads, and no instructions to attack external networks. Validation should be limited to owned, isolated lab addresses or the toy simulator provided here.
Attack Intuition
Private backend services are safe only if the network actually makes them private.
The Raspberry Pi gateway is supposed to be the choke point. It authenticates callers, enforces rate limits, applies payload limits, chooses Jetson versus Zynq, logs enough telemetry, and hides private backend details. If a client can connect directly to 192.168.30.10:8001 or 192.168.30.20:8002, the logical architecture on the diagram no longer matches the real packet path.
A5 is not about breaking a backend service. It is about discovering that the backend service was accidentally placed in the wrong exposure class: bound to all interfaces, bridged through the switch, reachable through a misconfigured VLAN, exposed through a host route, or published by a convenience port forward left over from development.
Safe framing: the demonstration below is a deterministic local simulator. It models reachability decisions from configuration data and synthetic packets; it does not scan any real network or contact Jetson, Zynq, or third-party systems.
Technical Explanation
A5 happens when backend reachability is broader than the intended trust boundary.
Service binding
A backend that listens on 0.0.0.0 or the wrong interface may be reachable from any routed segment. D4 prefers binding Jetson and Zynq services only to LAN2 addresses and rejecting non-Pi sources at the host firewall.
VLAN segmentation
The switch should keep client LAN and private LAN2 separate. A trunk, access-port mistake, bridge interface, or temporary test cable can flatten the topology and make the private zone reachable.
Gateway bypass
When direct backend access works, D1, D2, D3, D5, D6, and D8 may be bypassed because those controls live at the Pi path. Defense must exist both at network segmentation and backend host policy.
The clean design is defense in depth: switch VLAN rules prevent the path, Pi routing controls define the only intended route, backend host firewalls allow only the Pi LAN2 address, and backend services bind only to private interfaces. The gateway then becomes the deliberate policy point rather than a hopeful convention.
Mathematical Formulation
Model A5 as a reachability and policy-composition problem.
This framing makes A5 measurable. You can test a configuration by enumerating allowed and forbidden tuples, then proving that the forbidden set is empty while the required gateway paths remain available.
Step-By-Step Safe Lab Demonstration
The lab evaluates synthetic topology policies instead of probing real ports.
- Save the Python code from the next section as
a5_backend_exposure_policy_lab.py. - Run
python3 a5_backend_exposure_policy_lab.py --mode exposedto model a flat or misbound network. - Run
python3 a5_backend_exposure_policy_lab.py --mode isolatedto model D4 segmentation and backend allow-listing. - Compare
forbidden_allowed,required_allowed, andexposure_score. - Translate the same test table to your real lab documentation before any live validation. If you do live validation, keep it to owned addresses and record only defensive allow/drop evidence.
Interactive toy replay
Replay expected policy outcomes inside the page. It is display-only and never opens a socket.
Full Code For A Local Simulated Lab
This code computes allow/drop decisions for synthetic packets. It does not scan, connect, sniff, or attack anything.
#!/usr/bin/env python3
"""
A5 local-only simulator: direct backend exposure.
This program evaluates synthetic reachability decisions for an owned Edge AI
lab topology. It does not open sockets, scan ports, sniff traffic, or contact
Jetson/Zynq/Pi devices. Use it to reason about D4 policy before any real lab
validation.
"""
import argparse
from dataclasses import dataclass
from typing import Dict, List, Tuple
@dataclass(frozen=True)
class Host:
name: str
vlan: str
ip: str
@dataclass(frozen=True)
class Service:
host: str
port: int
bind: str
allowed_sources: Tuple[str, ...]
HOSTS: Dict[str, Host] = {
"client": Host("client", "client_vlan", "192.168.10.100"),
"pi_lan1": Host("pi_lan1", "client_vlan", "192.168.10.2"),
"pi_lan2": Host("pi_lan2", "private_lan2", "192.168.30.1"),
"jetson": Host("jetson", "private_lan2", "192.168.30.10"),
"zynq": Host("zynq", "private_lan2", "192.168.30.20"),
}
REQUIRED = [("pi_lan2", "jetson", 8001), ("pi_lan2", "zynq", 8002)]
FORBIDDEN = [("client", "jetson", 8001), ("client", "zynq", 8002)]
def build_services(mode: str) -> Dict[Tuple[str, int], Service]:
if mode == "exposed":
return {
("jetson", 8001): Service("jetson", 8001, "0.0.0.0", ("client", "pi_lan2")),
("zynq", 8002): Service("zynq", 8002, "0.0.0.0", ("client", "pi_lan2")),
}
return {
("jetson", 8001): Service("jetson", 8001, "192.168.30.10", ("pi_lan2",)),
("zynq", 8002): Service("zynq", 8002, "192.168.30.20", ("pi_lan2",)),
}
def vlan_allows(src: str, dst: str, mode: str) -> bool:
if src == "pi_lan2" and HOSTS[dst].vlan == "private_lan2":
return True
if mode == "exposed":
return True
return HOSTS[src].vlan == HOSTS[dst].vlan
def route_exists(src: str, dst: str, mode: str) -> bool:
if mode == "exposed":
return True
return src == "pi_lan2" and HOSTS[dst].vlan == "private_lan2"
def service_bound(service: Service, dst: str) -> bool:
return service.bind == "0.0.0.0" or service.bind == HOSTS[dst].ip
def firewall_allows(service: Service, src: str) -> bool:
return src in service.allowed_sources
def reachability(src: str, dst: str, port: int, mode: str) -> Tuple[bool, List[str]]:
services = build_services(mode)
service = services.get((dst, port))
reasons = []
if not service:
return False, ["no_service"]
checks = {
"route": route_exists(src, dst, mode),
"vlan": vlan_allows(src, dst, mode),
"service_bind": service_bound(service, dst),
"host_firewall": firewall_allows(service, src),
}
for name, ok in checks.items():
if not ok:
reasons.append("blocked_by_" + name)
return all(checks.values()), reasons or ["allowed"]
def evaluate(mode: str) -> int:
exposure_score = 0
print("mode=%s" % mode)
for src, dst, port in FORBIDDEN:
allowed, reasons = reachability(src, dst, port, mode)
if allowed:
exposure_score += 1
print(
"tuple=forbidden src=%s dst=%s port=%s decision=%s reasons=%s"
% (src, dst, port, "ALLOW" if allowed else "DROP", ",".join(reasons))
)
for src, dst, port in REQUIRED:
allowed, reasons = reachability(src, dst, port, mode)
print(
"tuple=required src=%s dst=%s port=%s decision=%s reasons=%s"
% (src, dst, port, "ALLOW" if allowed else "DROP", ",".join(reasons))
)
print("exposure_score=%s" % exposure_score)
return exposure_score
def main() -> None:
parser = argparse.ArgumentParser()
parser.add_argument("--mode", choices=["exposed", "isolated"], default="exposed")
args = parser.parse_args()
score = evaluate(args.mode)
if args.mode == "isolated" and score == 0:
print("result=pass d4_private_backend_subnet_enforced")
elif score > 0:
print("result=fail direct_backend_exposure_present")
else:
print("result=check_required_paths")
if __name__ == "__main__":
main()
# Vulnerable model: client can reach backend services directly in the synthetic policy.
python3 a5_backend_exposure_policy_lab.py --mode exposed
# Secure model: only Pi LAN2 can reach Jetson :8001 and Zynq :8002.
python3 a5_backend_exposure_policy_lab.py --mode isolated
# Expected secure result:
# tuple=forbidden src=client dst=jetson port=8001 decision=DROP ...
# tuple=forbidden src=client dst=zynq port=8002 decision=DROP ...
# result=pass d4_private_backend_subnet_enforced
Practical Example For Your GPU + Pi + Jetson + Zynq Setup
A5 is the question: can the MacBook reach the accelerators without passing through the Pi?
Intended topology
The MacBook or ThinkPad sits on the client side. It talks to the Pi gateway on LAN1. The Pi talks to Jetson and Zynq on LAN2. The switch/VLAN/private subnet design should make Jetson and Zynq invisible from the client path except through gateway-mediated inference.
A5 failure mode
A development shortcut exposes Jetson :8001 or Zynq :8002 to the client network. That might come from flat VLAN membership, service binding to all interfaces, host firewall gaps, a temporary bridge, or a switch port configured as trunk instead of access.
For your portal experiments, treat D4 as a measurable prerequisite. Before collecting inference latency, throughput, extraction-resistance, or fault-injection results, log the policy state that proves the Pi is the only source allowed to reach the backend services.
Observable Signals Or Logs
A5 should be visible as allow/drop evidence at the switch, Pi, and backend host layers.
| Layer | Risk signal | Healthy D4 signal |
|---|---|---|
| Switch / VLAN | Client port and backend port share the same reachable segment or trunk behavior unexpectedly allows backend traffic. | Client VLAN and LAN2 are separated; backend ports are access ports in private LAN2 only. |
| Pi gateway | Backend receives work not reflected in Pi request logs, meaning the gateway was bypassed. | Every backend request has a corresponding Pi log entry with user, route, backend, and policy decision. |
| Jetson host | Access logs show client-side source addresses instead of Pi LAN2 source. | Only Pi LAN2 source appears for inference service connections. |
| Zynq PS | REST shim sees client-side addresses or unmediated requests to FPGA control endpoints. | PS firewall allows Pi LAN2 only; unexpected source addresses are dropped before application logic. |
| Research logs | Benchmark results mix gateway-mediated and direct-backend paths. | Each run records topology hash, VLAN profile, firewall policy version, and backend source evidence. |
Impact Analysis
Direct backend exposure converts one controlled API into multiple uncontrolled APIs.
Confidentiality
Direct access can expose prediction outputs, confidence patterns, service banners, health metadata, backend timing, and model-oracle behavior without gateway identity binding.
Integrity
If backend control or management endpoints are reachable, a caller may bypass gateway-side object checks or dispatch policy. Even read-only inference bypass can compromise experiment integrity by mixing paths.
Availability
Jetson and Zynq services may be easier to overload directly because D2 rate limits, payload caps, and D8 timeout policy often live at the Pi boundary.
Mapping To CIA, STRIDE, PASTA, And MITRE ATLAS
A5 is a classic trust-boundary failure with AI-specific oracle and accelerator consequences.
| Framework | A5 mapping | Research interpretation |
|---|---|---|
| CIA | Confidentiality, Integrity, and Availability | The attacker bypasses gateway controls to reach model-serving backends and accelerator resources directly. |
| STRIDE | Information Disclosure, Tampering, Denial of Service, Elevation of Privilege, Repudiation | The path skips identity, audit, authorization, and rate-control layers normally enforced by the Pi. |
| PASTA | Stage 3 decomposition, Stage 4 threat analysis, Stage 5 vulnerability analysis, Stage 6 attack modeling | Model trust zones, data flows, and backend service exposure as first-class security assumptions. |
| MITRE ATLAS | Relevant to model access, discovery, collection, and AI service abuse patterns where an adversary reaches the serving endpoint outside intended controls. | A5 creates the unmediated model-oracle path that later attacks such as extraction, timing analysis, or backend-specific abuse can depend on. |
| MITRE ATT&CK | Related to network service discovery, exposed services, lateral movement pathways, and endpoint access control gaps. | Traditional network exposure becomes AI-specific because the reachable service is an accelerator-backed inference backend. |
Defense Mapping To Existing D1-D11 Controls
D4 is primary, but A5 shows why gateway and backend controls should reinforce each other.
| Control | Role against A5 | Validation |
|---|---|---|
| D4 Private Backend Subnet | Primary control. Put Jetson and Zynq on LAN2, bind services to private interfaces, enforce switch VLANs, and allow only Pi LAN2 as source. | Forbidden client-to-backend tuples drop; required Pi-to-backend tuples pass. |
| D1 JWT Auth + Object Checks | Protects the intended public path but can be bypassed if A5 exists. Backend services should still have minimal internal auth for defense in depth. | Direct backend calls cannot produce useful work without gateway identity or internal service credential. |
| D2 Rate Limit + Body Cap | Limits public gateway abuse but does not help if clients can skip the gateway. Backend host policy should provide secondary connection limits. | No backend request is observed without a matching Pi rate-limit decision. |
| D3 TLS Everywhere | Prevents cleartext on allowed paths and supports mTLS Pi-to-backend authentication. | Backends accept mTLS client identity from Pi only. |
| D5 Query Anomaly Detection | Detects model-oracle abuse only if telemetry includes all backend requests. A5 creates blind spots. | Backend logs and Pi logs reconcile one-to-one. |
| D6 Sanitized Logging | Provides evidence of gateway bypass by comparing backend source addresses and Pi request IDs. | Unexpected client source is logged as policy violation without storing sensitive payloads. |
| D8 Backend Timeout / Circuit Breaker | Protects gateway-mediated backend calls. Backend-local timeouts and process supervisors should also exist. | Direct overload paths are unavailable; gateway timeout metrics remain authoritative. |
Research Notes: What To Measure Experimentally
A5 can be measured with reachability matrices and log reconciliation, not dramatic traffic.
Reachability matrix
Enumerate source, destination, port, route, VLAN, firewall, and expected decision. The core metric is forbidden paths allowed versus required paths allowed.
Control-plane drift
Hash switch config, Pi firewall rules, backend service binding, and backend firewall state. Track whether exposure changes between experiments.
Log reconciliation
For every backend request, require a matching Pi gateway request ID. A mismatch indicates direct backend access, missing logging, or out-of-band maintenance traffic.
Benchmark contamination
Compare latency and throughput distributions for gateway-mediated paths versus direct backend paths in a safe, owned lab. Keep them separate in research results.
Key Takeaways
A private backend is a property you continuously verify, not a label on a diagram.
- A5 exists when Jetson or Zynq backend ports are reachable from the client side instead of only from Pi LAN2.
- The Pi gateway controls are meaningful only if traffic cannot bypass the Pi.
- D4 should be validated at multiple layers: service bind address, host firewall, Pi routing, switch VLANs, and log reconciliation.
- For research, record topology and reachability evidence beside every benchmark or security experiment.