AI Agent Instructions for Metasploit Framework
Project Overview
Metasploit Framework is an open-source penetration testing and exploitation framework written in Ruby. It provides infrastructure for developing, testing, and executing exploit code against remote targets.
Project Structure
modules/— Metasploit modules (exploits, auxiliary, post, payloads, encoders, evasion, nops)lib/msf/— Core framework library codelib/rex/— Rex (Ruby Exploitation) librarylib/metasploit/— Metasploit namespace librariesdata/— Data files used by modules (wordlists, templates, binaries)spec/— RSpec test suitetools/— Developer and operational toolsplugins/— msfconsole pluginsscripts/— Example automation scripts
Coding Conventions
Ruby (see
.ruby-versionfor the current version). Minimum supported: 3.1+Follow the project's
.rubocop.ymlconfiguration — runrubocopon changed files before submittingRun
msftidyto catch common module issuesAdd
# frozen_string_literal: trueto new files (the RuboCop cop is disabled project-wide for legacy code, but new files should include it)No enforced line length limit, but keep code readable
Use
%q{}for long multi-line strings (curly braces preferred for module descriptions)Multiline block comments are acceptable for embedded code snippets/payloads
Don't use
get_/set_prefixes for accessor methods in new codeMethod parameter names must be at least 2 characters (exception for well-known crypto abbreviations)
Module Development
Prefer writing modules in Ruby. Go and Python modules are accepted, but their external runtimes don't support the full framework API (e.g. network pivoting). Ruby modules do not have this limitation
Before writing a new module, check that there is not an existing module or open pull request that already covers the same functionality
Each module should be in its own file under the appropriate
modules/subdirectory. In some scenarios adding module actions or targets is preferred.Exploits require a
DisclosureDatefieldExploits, auxiliary, and post modules require
NoteswithSideEffectsUse the module mixin APIs — don't reinvent the wheel
Use
create_process(executable, args: [], time_out: 15, opts: {})instead of the deprecatedcmd_execwith separate argumentsLicense new code with
MSF_LICENSE(the project default, defined inlib/msf/core/constants.rb)When overriding
cleanup, always callsuperto ensure the parent mixin chain cleans up connections and sessions properlyWhen possible don't set a default payload (
DefaultOptionswith'PAYLOAD') in modules — let the framework choose the most appropriate payload automaticallyNew modules require an associated markdown file in the
documentation/modulesfolder with the same structure, including steps to set up the vulnerable environment for testingModule descriptions or documentation should list the range of vulnerable versions and the fixed version of the affected software, when known
report_servicemethod called when a service can be reportedreport_vulnmethod called when a vuln can be reportedWhen creating a fake account / username use FAKER not
rand_test_alphanumericAlways use
res.get_json_documentto convert an HTTP response to a hash instead of callingJSON.parse(res.body)If there's only one
ACTIONin the exploit, it can likely be omitted.Msf::Exploit::SQLishould be used if it's exploiting an SQLiAll
print_*calls should start with a capitalwhen opening a file, make sure the file exists first
when checking for a string in a response - will it always be in english?
Ensure hardcoded strings being regex'ed will be consistent across multiple versions
Use the TEST-NET-1 range for example / non-routeable IP address:
192.0.2.0Use fetch payload instead of command stagers when only options that request the stage are available (i.e. don’t use a cmd stager and only allow curl/wget).
Define bad characters instead of explicitly base-64 encoding payloads
Use
ARCH_CMDpayloads instead of command stagers when only curl/wget and other download mechanisms would be availableDon’t check the number of sessions at the end of an exploit and report success based on that, not all payloads open sessions
Don’t submit any kind of opaque binary blob, everything must include source code and build instructions
Don’t print host information like
#{ip}:#{port}because it doesn’t handle IPv6 addresses, instead use#{Rex::Socket.to_authority(ip, port)}Implement a
checkmethod when possible to allow users to verify vulnerability before exploitation
Check Methods
checkmethods must only returnCheckCodevalues (e.g.CheckCode::Vulnerable,CheckCode::Safe) — never raise exceptions or callfail_withWhen writing a
checkmethod, verify it does not produce false positives when run against unrelated software or servicesUse
fail_with(Failure::UnexpectedReply, '...')(and otherFailure::*constants) to bail out ofexploit/runmethods — don't useraiseor barereturnfor error conditionsget_versionmethods should return a REX versionCheckCode::Vulnerableis only used when the vulnerability has been exploitedCheckCode::Appearsis only used when the application's versions has been checked`Don't use a massive
<href .*dot star to grab the version, to be more precise.Do catch exceptions that may be raised and ensure a valid Check Code is returned
Do research and determine a minimum version where the application is vulnerable, mark prior versions as safe
Check helper methods that are used by both
#checkand#exploit(or#run) and make sure there is no condition (exception, return, etc) where#checkcould return something else than CheckCode.Prefer
prepend Msf::Exploit::Remote::AutoCheckover manually callingcheckinsideexploit— this lets the framework handle check-before-exploit automatically
Library Code
When adding complex binary or protocol parsing (e.g. BinData, RASN1, Rex::Struct2), include a code comment linking to the specification or RFC that defines the format being implemented
Write RSpec tests for any library changes
Follow Better Specs conventions
Write YARD documentation for public methods
Keep PRs focused — small fixes are easier to review
Any new hash cracking implementations require adding a test hash to
tools/dev/hash_cracker_validator.rband ensuring that passes without error
Testing
Tests live in
spec/mirroring thelib/structureRun tests with:
rspec spec/path/to/spec.rbUse
bundle exec rspecto ensure correct gem versions
Preferred Libraries
Use the
RubySMBlibrary for SMB modulesUse
Rex::Stopwatch.elapsed_timeto track elapsed timeUse the
Rex::MIME::Messageclass for MIME messages instead of hardcoding XMLWhen creating random variable names prefer
Rex::RandomIdentifier::Generatorand specify the runtime language used. This avoids generating langauge keywords that would break the script.
Common Patterns
Register options with
register_optionsandregister_advanced_optionsUse
SCREAMING_SNAKE_CASEoption names andCamelCaseadvanced option namesUse
datastore['OPTION_NAME']to access module optionsUse
print_status,print_good,print_error,print_warningfor console outputUse
vprint_*variants for verbose-only outputUse
send_request_cgifor HTTP requests in modulesUse
connect/disconnectfor TCP socket operations
Before Submitting
Ensure
rubocopandmsftidypass on any changed files with no new offensesEnsure
msftidy_docspasses on any changed documentation markdown docs with no new offenses
What NOT to Do
Don't submit untested code — all code must be manually verified
Don't include sensitive information (IPs, credentials, API keys, hashes of credentials) in code or docs
Don't include more than one module per pull request
Don't add new scripts to
scripts/— use post modules insteadDon't use
pack/unpackwith invalid directives (enforced by linter)