[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,9 @@
// Phase 21 — Apollo resolver benign control.
const _NYX_ADAPTER_MARKER = "require('@apollo/server')";
function resolveUser(parent, args, ctx) {
const id = String(args.id || '').replace(/[^A-Za-z0-9_-]/g, '');
return { id, name: 'user-' + id };
}
module.exports = { resolveUser };

View file

@ -0,0 +1,14 @@
// Phase 21 (Track M.3) — Apollo GraphQL resolver vuln fixture.
//
// `resolveUser(parent, args)` is a resolver from an Apollo schema that
// splices `args.id` into a SQL query via raw string concatenation —
// classic GraphQL → SQLi shape.
const _NYX_ADAPTER_MARKER = "require('@apollo/server')";
function resolveUser(parent, args, ctx) {
// SINK: tainted args.id concatenated into SQL.
const query = "SELECT * FROM users WHERE id = '" + args.id + "'";
return { id: args.id, name: 'user-' + args.id, _query: query };
}
module.exports = { resolveUser };

View file

@ -0,0 +1,15 @@
// Phase 21 — gqlgen benign control.
package benign
// import "github.com/99designs/gqlgen/graphql"
import "regexp"
var idAllow = regexp.MustCompile(`^[A-Za-z0-9_-]+$`)
func ResolveUser(id string) (string, error) {
if !idAllow.MatchString(id) {
return "", nil
}
return "user-" + id, nil
}

View file

@ -0,0 +1,23 @@
// Phase 21 (Track M.3) — gqlgen GraphQL resolver vuln fixture.
//
// `resolveUser(ctx, id)` is a gqlgen resolver (substring marker only —
// the real gqlgen runtime is not on the workdir's go.mod). The
// resolver splices the id into a shell command via os/exec.
package vuln
// import "github.com/99designs/gqlgen/graphql"
import (
"os/exec"
)
// type queryResolver struct{}
func ResolveUser(id string) (string, error) {
// SINK: tainted id concatenated into shell command.
out, err := exec.Command("/bin/sh", "-c", "echo lookup-"+id).Output()
if err != nil {
return "", err
}
return string(out), nil
}

View file

@ -0,0 +1,9 @@
"""Phase 21 — Graphene resolver benign control."""
import re
_NYX_ADAPTER_MARKER = "import graphene"
def resolve_user(self, info, id):
safe = re.sub(r"[^A-Za-z0-9_-]", "", str(id))
return "user-" + safe

View file

@ -0,0 +1,15 @@
"""Phase 21 (Track M.3) — Graphene resolver vuln fixture.
`resolve_user(self, info, id)` is a Graphene query resolver that
splices the tainted `id` into a shell command via `os.system`.
"""
import os
_NYX_ADAPTER_MARKER = "import graphene"
_NYX_OBJECT_TYPE_MARKER = "class Query(graphene.ObjectType):"
def resolve_user(self, info, id):
# SINK: tainted id concatenated into shell command.
os.system("echo lookup-" + str(id))
return "user-" + str(id)

View file

@ -0,0 +1,10 @@
//! Phase 21 — Juniper resolver benign control.
// use juniper::graphql_object;
pub fn resolve_user(id: &str) -> String {
let safe: String = id
.chars()
.filter(|c| c.is_ascii_alphanumeric() || *c == '_' || *c == '-')
.collect();
format!("user-{}", safe)
}

View file

@ -0,0 +1,15 @@
//! Phase 21 (Track M.3) — Juniper GraphQL resolver vuln fixture.
//!
//! `resolve_user(id)` is a Juniper resolver (substring marker only —
//! the real `juniper` crate is not on the workdir's Cargo.toml). The
//! resolver builds a SQL query via raw string concat — classic
//! GraphQL → SQLi shape.
// use juniper::graphql_object;
pub fn resolve_user(id: &str) -> String {
// SINK: tainted id concatenated into SQL.
let query = format!("SELECT * FROM users WHERE id = '{}'", id);
let _ = query;
format!("user-{}", id)
}

View file

@ -0,0 +1,9 @@
// Phase 21 — graphql-relay benign control.
const _NYX_ADAPTER_MARKER = "require('graphql-relay')";
function resolveNode(parent, args) {
const id = String(args.id || '').replace(/[^A-Za-z0-9_-]/g, '');
return { id };
}
module.exports = { resolveNode };

View file

@ -0,0 +1,10 @@
// Phase 21 (Track M.3) — graphql-relay vuln fixture.
const _NYX_ADAPTER_MARKER = "require('graphql-relay')";
function resolveNode(parent, args, ctx, info) {
// SINK: tainted globalId interpolated into SQL.
const sql = "SELECT * FROM nodes WHERE id = '" + args.id + "'";
return { id: args.id, _sql: sql };
}
module.exports = { resolveNode };

View file

@ -0,0 +1,18 @@
"""Phase 21 — Django middleware benign control."""
import os
import shlex
_NYX_ADAPTER_MARKER = "from django.utils.deprecation import MiddlewareMixin"
class AuditMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
os.system("echo " + shlex.quote(str(request.body)))
return self.get_response(request)
def audit(get_response):
return AuditMiddleware(get_response)

View file

@ -0,0 +1,23 @@
"""Phase 21 (Track M.3) — Django middleware vuln fixture.
`AuditMiddleware.__call__(request)` splices `request.body` into a shell
command via `os.system`.
"""
import os
_NYX_ADAPTER_MARKER = "from django.utils.deprecation import MiddlewareMixin"
class AuditMiddleware:
def __init__(self, get_response):
self.get_response = get_response
def __call__(self, request):
# SINK: tainted request body concatenated into shell command.
os.system("echo " + str(request.body))
return self.get_response(request)
# Module-level alias for the harness to resolve `audit` directly.
def audit(get_response):
return AuditMiddleware(get_response)

View file

@ -0,0 +1,11 @@
// Phase 21 — Express middleware benign control.
const _NYX_ADAPTER_MARKER = "require('express')";
function audit(req, res, next) {
const body = String(req.body || '');
if (body.length > 1024) return res.end('too large');
if (typeof next === 'function') next();
return 'ok';
}
module.exports = { audit };

View file

@ -0,0 +1,17 @@
// Phase 21 (Track M.3) — Express middleware vuln fixture.
//
// `audit(req, res, next)` is mounted via `app.use(audit)`. It splices
// the request body into a shell command via `execSync`.
const _NYX_ADAPTER_MARKER = "require('express')";
const _NYX_REGISTER_MARKER = "app.use(audit)";
const { execSync } = require('child_process');
function audit(req, res, next) {
// SINK: tainted req.body concatenated into shell command.
const out = execSync('echo ' + String(req.body || '')).toString();
if (typeof next === 'function') next();
return out;
}
module.exports = { audit };

View file

@ -0,0 +1,11 @@
<?php
// Phase 21 — Laravel middleware benign control.
// use Illuminate\\Http\\Request;
class Audit {
public function handle($request, $next) {
$body = is_object($request) && isset($request->body) ? (string)$request->body : (string)$request;
shell_exec("echo " . escapeshellarg($body));
return $next($request);
}
}

View file

@ -0,0 +1,17 @@
<?php
// Phase 21 (Track M.3) — Laravel middleware vuln fixture.
//
// `Audit::handle($request, $next)` splices `$request->body` into a
// shell command via `shell_exec` — classic Laravel middleware cmdi.
// use Illuminate\\Http\\Request;
// function handle($request, Closure $next)
class Audit {
public function handle($request, $next) {
$body = is_object($request) && isset($request->body) ? (string)$request->body : (string)$request;
// SINK: tainted body concatenated into shell command.
shell_exec("echo " . $body);
return $next($request);
}
}

View file

@ -0,0 +1,14 @@
# Phase 21 — Rack middleware benign control.
require 'shellwords'
class AuditMiddleware
def initialize(app)
@app = app
end
def call(env)
payload = (env['nyx.payload'] || env['QUERY_STRING']).to_s
system("echo " + Shellwords.escape(payload))
@app.call(env)
end
end

View file

@ -0,0 +1,17 @@
# Phase 21 (Track M.3) — Rack/Rails middleware vuln fixture.
#
# `AuditMiddleware#call(env)` splices `env['nyx.payload']` into a shell
# command — classic Rack-middleware cmdi shape.
class AuditMiddleware
def initialize(app)
@app = app
end
def call(env)
payload = env['nyx.payload'] || env['QUERY_STRING'].to_s
# SINK: tainted env value concatenated into shell command.
system("echo " + payload.to_s)
@app.call(env)
end
end

View file

@ -0,0 +1,10 @@
// Phase 21 Spring middleware benign control.
// implements HandlerInterceptor
public class Benign {
public boolean preHandle(String payload) {
String safe = payload.replaceAll("[^A-Za-z0-9 _.-]", "_");
System.out.println("intercepted: " + safe);
return true;
}
}

View file

@ -0,0 +1,16 @@
// Phase 21 (Track M.3) Spring HandlerInterceptor middleware vuln
// fixture.
//
// `Vuln#preHandle` splices the request body into a shell command via
// Runtime.exec. HandlerInterceptor is referenced as a substring
// marker only.
//
// implements HandlerInterceptor
public class Vuln {
public boolean preHandle(String payload) throws Exception {
// SINK: tainted payload concatenated into shell command.
Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", "echo " + payload });
return true;
}
}

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';
};

View file

@ -0,0 +1,9 @@
"""Phase 21 — Celery scheduled-task benign control."""
import os
import shlex
_NYX_ADAPTER_MARKER = "from celery import shared_task"
def tick(payload):
os.system("echo " + shlex.quote(str(payload)))

View file

@ -0,0 +1,15 @@
"""Phase 21 (Track M.3) — Celery scheduled-task vuln fixture.
`tick(payload)` is a Celery task that splices the payload bytes into a
shell command via `os.system`. An attacker who can enqueue a task with
arbitrary bytes can inject shell metacharacters.
"""
import os
_NYX_ADAPTER_MARKER = "from celery import shared_task"
_NYX_DECORATOR_MARKER = "@shared_task"
def tick(payload):
# SINK: tainted payload concatenated into shell command.
os.system("echo " + str(payload))

View file

@ -0,0 +1,9 @@
// Phase 21 — node-cron benign control.
const _NYX_ADAPTER_MARKER = "require('node-cron')";
const _NYX_SCHEDULE_MARKER = "cron.schedule('*/5 * * * *', tick)";
function tick(payload) {
return 'tick: ' + JSON.stringify(payload);
}
module.exports = { tick };

View file

@ -0,0 +1,17 @@
// Phase 21 (Track M.3) — node-cron scheduled-job vuln fixture.
//
// `tick(payload)` is a job registered with `cron.schedule(...)` that
// splices the payload into a child-process command. An attacker who
// can stage payload bytes into the job's input source can inject
// shell metacharacters.
const _NYX_ADAPTER_MARKER = "require('node-cron')";
const _NYX_SCHEDULE_MARKER = "cron.schedule('*/5 * * * *', tick)";
const { execSync } = require('child_process');
function tick(payload) {
// SINK: tainted payload concatenated into shell command.
return execSync('echo ' + String(payload)).toString();
}
module.exports = { tick };

View file

@ -0,0 +1,8 @@
// Phase 21 Quartz benign control.
// org.quartz.Job marker (substring scan only).
public class Benign {
public void execute(String payload) {
System.out.println("scheduled: " + payload.replaceAll("[^A-Za-z0-9 _.-]", "_"));
}
}

View file

@ -0,0 +1,16 @@
// Phase 21 (Track M.3) Quartz scheduled-job vuln fixture.
//
// `Vuln` implements the Quartz `Job` interface (substring-marker only
// the real `org.quartz.Job` symbol is not on the JDK classpath).
// `execute(JobExecutionContext)` splices the payload into a shell
// command via `Runtime.exec`, the classic Quartz job cmdi shape.
// org.quartz.Job marker (substring scan only not a real import).
// @DisallowConcurrentExecution
public class Vuln {
public void execute(String payload) throws Exception {
// SINK: tainted payload concatenated into shell command.
Runtime.getRuntime().exec(new String[] { "/bin/sh", "-c", "echo " + payload });
}
}

View file

@ -0,0 +1,10 @@
# Phase 21 — Sidekiq benign control.
# include Sidekiq::Worker
require 'shellwords'
class TickWorker
def perform(payload)
system("echo " + Shellwords.escape(payload.to_s))
end
end

View file

@ -0,0 +1,20 @@
# Phase 21 (Track M.3) — Sidekiq scheduled-job vuln fixture.
#
# `TickWorker` includes the Sidekiq::Worker mixin (substring marker
# only — the real Sidekiq gem is not loaded). `perform(payload)`
# splices the payload into a shell command via Kernel#system, the
# classic worker cmdi shape.
# include Sidekiq::Worker
# sidekiq_options queue: :default
class TickWorker
def self.included_modules
[:'Sidekiq::Worker']
end
def perform(payload)
# SINK: tainted payload concatenated into shell command.
system("echo " + payload.to_s)
end
end

View file

@ -0,0 +1,9 @@
# Phase 21 — ActionCable benign control.
# class ChatChannel < ApplicationCable::Channel
require 'shellwords'
class ChatChannel
def receive(data)
system("echo " + Shellwords.escape(data.to_s))
end
end

View file

@ -0,0 +1,14 @@
# Phase 21 (Track M.3) — Rails ActionCable channel vuln fixture.
#
# `ChatChannel#receive(data)` splices the inbound WebSocket message
# bytes into a shell command via Kernel#system — classic ActionCable
# → cmdi shape.
# class ChatChannel < ApplicationCable::Channel
class ChatChannel
def receive(data)
# SINK: tainted data concatenated into shell command.
system("echo " + data.to_s)
end
end

View file

@ -0,0 +1,15 @@
"""Phase 21 — Django Channels benign control."""
import os
import shlex
_NYX_ADAPTER_MARKER = "from channels.generic.websocket import WebsocketConsumer"
class ChatConsumer:
def receive(self, text_data=None, bytes_data=None):
payload = text_data if text_data is not None else (bytes_data or b"").decode("utf-8", "replace")
os.system("echo " + shlex.quote(str(payload)))
def receive(text_data=None, bytes_data=None):
return ChatConsumer().receive(text_data, bytes_data)

View file

@ -0,0 +1,20 @@
"""Phase 21 (Track M.3) — Django Channels WebsocketConsumer vuln fixture.
`ChatConsumer.receive(text_data=None, bytes_data=None)` splices the
inbound frame into a shell command via `os.system`.
"""
import os
_NYX_ADAPTER_MARKER = "from channels.generic.websocket import WebsocketConsumer"
class ChatConsumer:
def receive(self, text_data=None, bytes_data=None):
payload = text_data if text_data is not None else (bytes_data or b"").decode("utf-8", "replace")
# SINK: tainted frame body concatenated into shell command.
os.system("echo " + str(payload))
# Module-level alias for the harness to resolve `receive` directly.
def receive(text_data=None, bytes_data=None):
return ChatConsumer().receive(text_data, bytes_data)

View file

@ -0,0 +1,9 @@
"""Phase 21 — python-socketio benign control."""
import os
import shlex
_NYX_ADAPTER_MARKER = "import socketio"
def message(sid, data):
os.system("echo " + shlex.quote(str(data)))

View file

@ -0,0 +1,14 @@
"""Phase 21 (Track M.3) — python-socketio handler vuln fixture.
`message(sid, data)` is a Socket.IO event handler. It splices the
inbound message into a shell command via `os.system`.
"""
import os
_NYX_ADAPTER_MARKER = "import socketio"
_NYX_EVENT_MARKER = "@sio.on('message')"
def message(sid, data):
# SINK: tainted message body concatenated into shell command.
os.system("echo " + str(data))

View file

@ -0,0 +1,8 @@
// Phase 21 — `ws` WebSocket benign control.
const _NYX_ADAPTER_MARKER = "require('ws')";
function onMessage(data) {
return 'echoed: ' + JSON.stringify(String(data));
}
module.exports = { onMessage };

View file

@ -0,0 +1,15 @@
// Phase 21 (Track M.3) — `ws` WebSocket handler vuln fixture.
//
// `onMessage(data)` is the `on('message', ...)` listener on a
// WebSocketServer instance. It splices the message bytes into a
// child-process command — classic WS → cmdi shape.
const _NYX_ADAPTER_MARKER = "require('ws')";
const { execSync } = require('child_process');
function onMessage(data) {
// SINK: tainted message body concatenated into shell command.
return execSync('echo ' + String(data)).toString();
}
module.exports = { onMessage };