mirror of
https://github.com/elicpeter/nyx.git
synced 2026-06-12 19:55:14 +02:00
[pitboss] phase 21: Track M.3 — ScheduledJob + GraphQLResolver + WebSocket + Middleware + Migration
This commit is contained in:
parent
00b0fbaea9
commit
f9bd51c024
84 changed files with 5898 additions and 40 deletions
11
tests/dynamic_fixtures/migration/django/benign.py
Normal file
11
tests/dynamic_fixtures/migration/django/benign.py
Normal 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 = []
|
||||
23
tests/dynamic_fixtures/migration/django/vuln.py
Normal file
23
tests/dynamic_fixtures/migration/django/vuln.py
Normal 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 = []
|
||||
8
tests/dynamic_fixtures/migration/flask/benign.py
Normal file
8
tests/dynamic_fixtures/migration/flask/benign.py
Normal 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"
|
||||
22
tests/dynamic_fixtures/migration/flask/vuln.py
Normal file
22
tests/dynamic_fixtures/migration/flask/vuln.py
Normal 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")
|
||||
13
tests/dynamic_fixtures/migration/laravel/benign.php
Normal file
13
tests/dynamic_fixtures/migration/laravel/benign.php
Normal 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;
|
||||
}
|
||||
}
|
||||
25
tests/dynamic_fixtures/migration/laravel/vuln.php
Normal file
25
tests/dynamic_fixtures/migration/laravel/vuln.php
Normal 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";
|
||||
}
|
||||
}
|
||||
10
tests/dynamic_fixtures/migration/prisma/benign.js
Normal file
10
tests/dynamic_fixtures/migration/prisma/benign.js
Normal 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 };
|
||||
17
tests/dynamic_fixtures/migration/prisma/vuln.js
Normal file
17
tests/dynamic_fixtures/migration/prisma/vuln.js
Normal 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 };
|
||||
12
tests/dynamic_fixtures/migration/rails/benign.rb
Normal file
12
tests/dynamic_fixtures/migration/rails/benign.rb
Normal 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
|
||||
23
tests/dynamic_fixtures/migration/rails/vuln.rb
Normal file
23
tests/dynamic_fixtures/migration/rails/vuln.rb
Normal 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
|
||||
12
tests/dynamic_fixtures/migration/sequelize/benign.js
Normal file
12
tests/dynamic_fixtures/migration/sequelize/benign.js
Normal 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'; };
|
||||
21
tests/dynamic_fixtures/migration/sequelize/vuln.js
Normal file
21
tests/dynamic_fixtures/migration/sequelize/vuln.js
Normal 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';
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue