Panther is a tool designed to find common security issues in Node.js code. To do this Panther processes each file, builds an AST from it, and runs appropriate plugins against the AST nodes. Once Panther has finished scanning all the files it generates a report.
Install Panther:
git clone https://github.com/Yhnlvy/panther.git && cd panther
python3 setup.py install
Run Panther:
panther -r path/to/your/code
Example usage across a code tree:
panther -r ~/itc-repo/keystone
Example usage across the examples/
directory, showing three lines of context and only reporting on the high-severity issues:
panther examples/*.js -n 3 -lll
Panther can be run with profiles. To run Panther against the examples directory using only the plugins listed in the ShellInjection
profile:
panther examples/*.js -p ShellInjection
Panther also supports passing lines of code to scan using standard input. To run Panther with standard input:
cat examples/sql_injection.js | panther -
Usage:
$ panther -h
usage: panther [-h] [-r] [-a {file,vuln}] [-n CONTEXT_LINES] [-c CONFIG_FILE]
[-p PROFILE] [-t TESTS] [-s SKIPS] [-l] [-i]
[-f {csv,custom,html,json,screen,txt,xml,yaml}]
[--msg-template MSG_TEMPLATE] [-o [OUTPUT_FILE]] [-v] [-d]
[--ignore-nosec] [-x EXCLUDED_PATHS] [-b BASELINE]
[--ini INI_PATH] [--version]
[targets [targets ...]]
Panther - a Node.js source code security analyzer
positional arguments:
targets source file(s) or directory(s) to be tested
optional arguments:
-h, --help show this help message and exit
-r, --recursive find and process files in subdirectories
-a {file,vuln}, --aggregate {file,vuln}
aggregate output by vulnerability (default) or by
filename
-n CONTEXT_LINES, --number CONTEXT_LINES
maximum number of code lines to output for each issue
-c CONFIG_FILE, --configfile CONFIG_FILE
optional config file to use for selecting plugins and
overriding defaults
-p PROFILE, --profile PROFILE
profile to use (defaults to executing all tests)
-t TESTS, --tests TESTS
comma-separated list of test IDs to run
-s SKIPS, --skip SKIPS
comma-separated list of test IDs to skip
-l, --level report only issues of a given severity level or higher
(-l for LOW, -ll for MEDIUM, -lll for HIGH)
-i, --confidence report only issues of a given confidence level or
higher (-i for LOW, -ii for MEDIUM, -iii for HIGH)
-f {csv,custom,html,json,screen,txt,xml,yaml}, --format {csv,custom,html,json,screen,txt,xml,yaml}
specify output format
--msg-template MSG_TEMPLATE
specify output message template (only usable with
--format custom), see CUSTOM FORMAT section for list
of available values
-o [OUTPUT_FILE], --output [OUTPUT_FILE]
write report to filename
-v, --verbose output extra information like excluded and included
files
-d, --debug turn on debug mode
--ignore-nosec do not skip lines with # nosec comments
-x EXCLUDED_PATHS, --exclude EXCLUDED_PATHS
comma-separated list of paths to exclude from scan
(note that these are in addition to the excluded paths
provided in the config file)
-b BASELINE, --baseline BASELINE
path of a baseline report to compare against (only
JSON-formatted files are accepted)
--ini INI_PATH path to a .panther file that supplies command line
arguments
--version show program's version number and exit
--nsp scan the package.json to find vulnerable dependencies
CUSTOM FORMATTING
-----------------
Available tags:
{abspath}, {relpath}, {line}, {test_id},
{severity}, {msg}, {confidence}, {range}
Example usage:
Default template:
panther -r examples/ --format custom --msg-template \
"{abspath}:{line}: {test_id}[panther]: {severity}: {msg}"
Provides same output as:
panther -r examples/ --format custom
Tags can also be formatted in python string.format() style:
panther -r examples/ --format custom --msg-template \
"{relpath:20.20s}: {line:03}: {test_id:^8}: DEFECT: {msg:>20}"
See python documentation for more information about formatting style:
https://docs.python.org/3.4/library/string.html
The following tests were discovered and loaded:
-----------------------------------------------
P601 server_side_injection
P602 sql_injection
Example usage across a code tree:
panther-baseline -r app/ --diff-only --commit 6ce647fd
Usage:
$ panther-baseline -h
usage: panther-baseline [-h] [-f {txt,html,json}] [--commit COMMIT_SHA]
[--diff-only]
targets [targets ...]
Panther Baseline - Generates Panther results compared to a baseline
positional arguments:
targets source file(s) or directory(s) to be tested
optional arguments:
-h, --help show this help message and exit
-f {txt,html,json} specify output format
--commit COMMIT_SHA commit sha to be tested
--diff-only run analysis on changed files only
Additional Panther arguments such as severity filtering (-ll) can be added and will be passed to Panther.
Example usage across a code tree:
python3 panther/core/tracer/main.py examples/tracer/basic.js --depth 2
Usage:
$ python3 panther/core/tracer/main.py -h
Panther Backtracer - automatically fetches route definition and performs a sink to source analysis
positional arguments:
entry_points entry points of the project where the routes are defined
optional arguments:
-h, --help show this help message and exit
-d, --debug turn on debug mode
--depth DEPTH maximum analysis depth to backtrace vulnerabilities
- An optional config file may be supplied and may include:
- lists of tests which should or shouldn't be run
- exclude_dirs - sections of the path, that if matched, will be excluded from scanning
- overridden plugin settings - may provide different settings for some plugins
Projects may include a .panther file that specifies command line arguments that should be supplied for that project. The currently supported arguments are:
- targets: comma separated list of target dirs/files to run panther on
- exclude: comma separated list of excluded paths
- skips: comma separated list of tests to skip
- tests: comma separated list of tests to run
To use this, put a .panther file in your project's directory. For example:
[panther]
exclude: /test
[panther]
tests: P601,P602
In the event that a line of code triggers a Panther issue, but that the line has been reviewed and the issue is a false positive or acceptable for some other reason, the line can be marked with a // nosec
and any results associated with it will not be reported.
For example, although this line may cause Panther to report a potential security issue, it will not be reported:
var cmd = eval(user_input) // nosec
Vulnerability tests or "plugins" are defined in files in the plugins directory.
Tests are written in Python and are autodiscovered from the plugins directory. Each test can examine one or more type of Python statements. Tests are marked with the types of Python statements they examine (for example: function call, string, import, etc).
Tests are executed by the PantherNodeVisitor
object as it visits each node in the AST.
Test results are maintained in the PantherResultStore
and aggregated for output at the completion of a test run.
- To write a test:
- Identify a vulnerability to build a test for, and create a new file in examples/ that contains one or more cases of that vulnerability.
- Consider the vulnerability you're testing for, mark the function with one or more of the appropriate decorators:
- @test.checks('CallExpression')
- @test.checks('TemplateLiteral')
- @test.checks('BinaryExpression')
- Create a new Python source file to contain your test, you can reference existing tests for examples.
- The function that you create should take a parameter "context" which is an instance of the context class you can query for information about the current element being examined. You can also get the raw AST node for more advanced use cases. Please see the context.py file for more.
- Extend your Panther configuration file as needed to support your new test.
- Execute Panther against the test file you defined in examples/ and ensure that it detects the vulnerability. Consider variations on how this vulnerability might present itself and extend the example file and the test function accordingly.
Panther allows users to write and register extensions for checks and formatters. Panther will load plugins from two entry-points:
- panther.formatters
- panther.plugins
Formatters need to accept 4 things:
- `result_store`: An instance of panther.core.PantherResultStore
- `file_list`: The list of files which were inspected in the scope
- `scores`: The scores awarded to each file in the scope
- `excluded_files`: The list of files that were excluded from the scope
Plugins tend to take advantage of the test.checks decorator which allows the author to register a check for a particular type of AST node. For example
@test.checks('CallExpression')
def eval_used(context):
"""Detect the use of eval"""
try:
if context.node.callee.name == 'eval':
return panther.Issue(
severity=panther.LOW,
confidence=panther.MEDIUM,
text=("How dare you? eval()? Really?: '%s'" % value))
except Exception:
pass
To register your plugin, you have two options:
If you're using setuptools directly, add something like the following to your
setup
call:# If you have an imaginary bson formatter in the panther_bson module # and a function called `formatter`. entry_points={'panther.formatters': ['bson = panther_bson:formatter']} # Or a check for using mako templates in panther_mako that entry_points={'panther.plugins': ['mako = panther_mako']}
If you're using pbr, add something like the following to your setup.cfg file:
[entry_points] panther.formatters = html = panther.formatters.html:report panther.plugins = eval_used = panther.plugins.js_server_side_injection:eval_used
You can test any changes with tox:
pip install tox
tox -e tests
tox -e pep8
- Bandit (OpenStack)
- PyEsprima (Js2Py, PiotrDabkowski)
- Esprima AST Visitor (austinbyers)
- Esprima (jQuery)
- Node Security Platform (nsp) (nodesecurity)