[pitboss] phase 21: Track M.3 — ScheduledJob + GraphQLResolver + WebSocket + Middleware + Migration

This commit is contained in:
pitboss 2026-05-20 18:05:31 -05:00
parent 00b0fbaea9
commit f9bd51c024
84 changed files with 5898 additions and 40 deletions

View file

@ -0,0 +1,11 @@
"""Phase 21 — Django migration benign control."""
_NYX_ADAPTER_MARKER = "from django.db import migrations"
def upgrade(table_name="users"):
safe = "".join(c for c in str(table_name) if c.isalnum() or c == "_")
return "CREATE INDEX idx_" + safe + " ON users(name)"
class Migration:
operations = []

View file

@ -0,0 +1,23 @@
"""Phase 21 (Track M.3) — Django migration vuln fixture.
The migration declares `operations = [...]` with a
`migrations.RunSQL` op whose statement is built from an external
table name via raw string concatenation.
"""
_NYX_ADAPTER_MARKER = "from django.db import migrations"
class _RunSQL:
def __init__(self, sql):
self.sql = sql
def upgrade(table_name="users"):
# SINK: tainted table name spliced into raw DDL.
sql = "CREATE INDEX idx_" + str(table_name) + " ON users(name)"
op = _RunSQL(sql)
return op
class Migration:
operations = []

View file

@ -0,0 +1,8 @@
"""Phase 21 — Alembic benign control."""
_NYX_ADAPTER_MARKER = "from alembic import op"
revision = "deadbeef0001"
def upgrade(column_name="email"):
safe = "".join(c for c in str(column_name) if c.isalnum() or c == "_")
return "ALTER TABLE users ADD COLUMN " + safe + " TEXT"

View file

@ -0,0 +1,22 @@
"""Phase 21 (Track M.3) — Flask-Migrate / Alembic migration vuln.
Alembic revisions declare an `upgrade()` function that issues DDL
through `op.execute(...)`. The vuln fixture splices a tainted column
name into the statement via raw string concat.
"""
_NYX_ADAPTER_MARKER = "from alembic import op"
revision = "abc123def4"
down_revision = None
class _Op:
def execute(self, sql):
print("ALEMBIC_SQL:", sql)
op = _Op()
def upgrade(column_name="email"):
# SINK: tainted column name spliced into raw DDL.
op.execute("ALTER TABLE users ADD COLUMN " + str(column_name) + " TEXT")

View file

@ -0,0 +1,13 @@
<?php
// Phase 21 — Laravel migration benign control.
// use Illuminate\\Database\\Migrations\\Migration;
class AddUsers {
public function up() {
$col = getenv('NYX_PAYLOAD') ?: 'email';
$safe = preg_replace('/[^A-Za-z0-9_]/', '_', $col);
$stmt = "ALTER TABLE users ADD COLUMN " . $safe . " TEXT";
echo "LARAVEL_SQL: " . $stmt . "\n";
return $stmt;
}
}

View file

@ -0,0 +1,25 @@
<?php
// Phase 21 (Track M.3) — Laravel migration vuln fixture.
//
// `AddUsers::up()` invokes `Schema::table` via a class-static
// fallthrough but splices a tainted column name into a raw
// `DB::statement` call.
// use Illuminate\\Database\\Migrations\\Migration;
// use Illuminate\\Database\\Schema;
class AddUsers {
public function up() {
$col = getenv('NYX_PAYLOAD') ?: 'email';
// SINK: tainted column name concatenated into raw DDL.
$stmt = "ALTER TABLE users ADD COLUMN " . $col . " TEXT";
DBStatementWrapper::statement($stmt);
return $stmt;
}
}
class DBStatementWrapper {
public static function statement($sql) {
echo "LARAVEL_SQL: " . $sql . "\n";
}
}

View file

@ -0,0 +1,10 @@
// Phase 21 — Prisma migration benign control.
const _NYX_ADAPTER_MARKER = "require('@prisma/client')";
async function up(name) {
const safe = String(name || process.env.NYX_PAYLOAD || 'users').replace(/[^A-Za-z0-9_]/g, '_');
const prisma = global.__nyx_prisma || { $executeRawUnsafe: async (s) => s };
return prisma.$executeRawUnsafe('CREATE INDEX idx_' + safe + ' ON users(name)');
}
module.exports = { up };

View file

@ -0,0 +1,17 @@
// Phase 21 (Track M.3) — Prisma migration vuln fixture.
//
// `up(name)` runs a raw DDL through `prisma.$executeRawUnsafe` —
// classic Prisma migration SQLi shape.
const _NYX_ADAPTER_MARKER = "require('@prisma/client')";
async function up(name) {
const target = name || process.env.NYX_PAYLOAD || 'users';
// The harness supplies a stubbed `prisma` shim via the synthetic
// migration entry path; we route through a module-level stub so the
// sink callee is statically present.
const prisma = global.__nyx_prisma || { $executeRawUnsafe: async (s) => s };
// SINK: tainted table name concatenated into raw DDL.
return prisma.$executeRawUnsafe('CREATE INDEX idx_' + target + ' ON users(name)');
}
module.exports = { up };

View file

@ -0,0 +1,12 @@
# Phase 21 — Rails migration benign control.
# class AddIndex < ActiveRecord::Migration[7.0]
class AddIndex
def up
add_column :users, :name, :string
end
def add_column(table, name, type)
puts "MIGRATION_ADD_COLUMN: #{table}.#{name} :: #{type}"
end
end

View file

@ -0,0 +1,23 @@
# Phase 21 (Track M.3) — Rails ActiveRecord migration vuln fixture.
#
# `AddIndex#up` invokes `execute(...)` with a raw, attacker-controlled
# table name concatenated into DDL — classic Rails migration SQLi.
# class AddIndex < ActiveRecord::Migration[7.0]
class AddIndex
attr_accessor :table_name
def up
name = @table_name || ENV['NYX_PAYLOAD'].to_s
# SINK: tainted table name spliced into raw DDL.
execute("CREATE INDEX idx_#{name} ON users(name)")
end
def execute(sql)
# The harness only asserts that execute() is invoked with the
# tainted SQL string. A real ActiveRecord::Base.connection would
# forward to the DB driver.
puts "MIGRATION_SQL: #{sql}"
end
end

View file

@ -0,0 +1,12 @@
// Phase 21 — Sequelize benign control.
const _NYX_ADAPTER_MARKER = "queryInterface.createTable";
module.exports.up = async function (queryInterface, Sequelize) {
const name = (process.env.NYX_PAYLOAD || 'users').replace(/[^A-Za-z0-9_]/g, '_');
if (queryInterface && typeof queryInterface.addColumn === 'function') {
await queryInterface.addColumn(name, 'description', { type: 'TEXT' });
}
return 'addColumn(' + name + ')';
};
module.exports.down = async function () { return 'noop'; };

View file

@ -0,0 +1,21 @@
// Phase 21 (Track M.3) — Sequelize migration vuln fixture.
//
// `up(queryInterface, Sequelize)` is the canonical migration entry
// point. This fixture builds a raw DDL string from an attacker-
// controlled table name and routes it through `queryInterface.sequelize.query`.
const _NYX_ADAPTER_MARKER = "queryInterface.createTable";
module.exports.up = async function (queryInterface, Sequelize) {
const name = process.env.NYX_PAYLOAD || 'users';
// SINK: tainted table name concatenated into raw DDL.
const sql = 'CREATE INDEX idx_' + name + ' ON users(name)';
if (queryInterface && queryInterface.sequelize && queryInterface.sequelize.query) {
await queryInterface.sequelize.query(sql);
}
return sql;
};
module.exports.down = async function (queryInterface, Sequelize) {
// benign in the down direction.
return 'DROP INDEX idx_users';
};