New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

python-taint

Package Overview
Dependencies
Maintainers
3
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

python-taint - pypi Package Compare versions

Comparing version
0.39
to
0.40
+104
pyt/formatters/screen.py
"""This formatter outputs the issues as color-coded text."""
from ..vulnerabilities.vulnerability_helper import SanitisedVulnerability, UnknownVulnerability
RESET = '\033[0m'
BOLD = '\033[1m'
UNDERLINE = '\033[4m'
DANGER = '\033[31m'
GOOD = '\033[32m'
HIGHLIGHT = '\033[45;1m'
RED_ON_WHITE = '\033[31m\033[107m'
def color(string, color_string):
return color_string + str(string) + RESET
def report(
vulnerabilities,
fileobj,
print_sanitised,
):
"""
Prints issues in color-coded text format.
Args:
vulnerabilities: list of vulnerabilities to report
fileobj: The output file object, which may be sys.stdout
"""
n_vulnerabilities = len(vulnerabilities)
unsanitised_vulnerabilities = [v for v in vulnerabilities if not isinstance(v, SanitisedVulnerability)]
n_unsanitised = len(unsanitised_vulnerabilities)
n_sanitised = n_vulnerabilities - n_unsanitised
heading = "{} vulnerabilit{} found{}.\n".format(
'No' if n_unsanitised == 0 else n_unsanitised,
'y' if n_unsanitised == 1 else 'ies',
" (plus {} sanitised)".format(n_sanitised) if n_sanitised else "",
)
vulnerabilities_to_print = vulnerabilities if print_sanitised else unsanitised_vulnerabilities
with fileobj:
for i, vulnerability in enumerate(vulnerabilities_to_print, start=1):
fileobj.write(vulnerability_to_str(i, vulnerability))
if n_unsanitised == 0:
fileobj.write(color(heading, GOOD))
else:
fileobj.write(color(heading, DANGER))
def vulnerability_to_str(i, vulnerability):
lines = []
lines.append(color('Vulnerability {}'.format(i), UNDERLINE))
lines.append('File: {}'.format(color(vulnerability.source.path, BOLD)))
lines.append(
'User input at line {}, source "{}":'.format(
vulnerability.source.line_number,
color(vulnerability.source_trigger_word, HIGHLIGHT),
)
)
lines.append('\t{}'.format(color(vulnerability.source.label, RED_ON_WHITE)))
if vulnerability.reassignment_nodes:
previous_path = None
lines.append('Reassigned in:')
for node in vulnerability.reassignment_nodes:
if node.path != previous_path:
lines.append('\tFile: {}'.format(node.path))
previous_path = node.path
label = node.label
if (
isinstance(vulnerability, SanitisedVulnerability) and
node.label == vulnerability.sanitiser.label
):
label = color(label, GOOD)
lines.append(
'\t Line {}:\t{}'.format(
node.line_number,
label,
)
)
if vulnerability.source.path != vulnerability.sink.path:
lines.append('File: {}'.format(color(vulnerability.sink.path, BOLD)))
lines.append(
'Reaches line {}, sink "{}"'.format(
vulnerability.sink.line_number,
color(vulnerability.sink_trigger_word, HIGHLIGHT),
)
)
lines.append('\t{}'.format(
color(vulnerability.sink.label, RED_ON_WHITE)
))
if isinstance(vulnerability, SanitisedVulnerability):
lines.append(
'This vulnerability is {}{} by {}'.format(
color('potentially ', BOLD) if not vulnerability.confident else '',
color('sanitised', GOOD),
color(vulnerability.sanitiser.label, BOLD),
)
)
elif isinstance(vulnerability, UnknownVulnerability):
lines.append(
'This vulnerability is unknown due to "{}"'.format(
color(vulnerability.unknown_assignment.label, BOLD),
)
)
return '\n'.join(lines) + '\n\n'
+2
-3
Metadata-Version: 1.1
Name: python-taint
Version: 0.39
Version: 0.40
Summary: Find security vulnerabilities in Python web applications using static analysis.

@@ -9,4 +9,3 @@ Home-page: https://github.com/python-security/pyt

License: GPLv2
Download-URL: https://github.com/python-security/pyt/archive/0.39.tar.gz
Description-Content-Type: UNKNOWN
Download-URL: https://github.com/python-security/pyt/archive/0.40.tar.gz
Description: Check out PyT on `GitHub <https://github.com/python-security/pyt>`_!

@@ -13,0 +12,0 @@ Keywords: security,vulnerability,web,flask,django,static-analysis,program-analysis

+23
-16
"""The comand line module of PyT."""
import logging
import os

@@ -15,11 +16,6 @@ import sys

)
from .formatters import (
json,
text
)
from .usage import parse_args
from .vulnerabilities import (
find_vulnerabilities,
get_vulnerabilities_not_in_baseline,
UImode
get_vulnerabilities_not_in_baseline
)

@@ -35,3 +31,5 @@ from .vulnerabilities.vulnerability_helper import SanitisedVulnerability

log = logging.getLogger(__name__)
def discover_files(targets, excluded_files, recursive=False):

@@ -47,2 +45,3 @@ included_files = list()

included_files.append(fullpath)
log.debug('Discovered file: %s', fullpath)
if not recursive:

@@ -53,2 +52,3 @@ break

included_files.append(target)
log.debug('Discovered file: %s', target)
return included_files

@@ -72,5 +72,9 @@

ui_mode = UImode.TRIM
if args.interactive:
ui_mode = UImode.INTERACTIVE
logging_level = (
logging.ERROR if not args.verbose else
logging.WARN if args.verbose == 1 else
logging.INFO if args.verbose == 2 else
logging.DEBUG
)
logging.basicConfig(level=logging_level, format='[%(levelname)s] %(name)s: %(message)s')

@@ -91,2 +95,3 @@ files = discover_files(

for path in sorted(files):
log.info("Processing %s", path)
if not args.ignore_nosec:

@@ -129,8 +134,10 @@ nosec_lines[path] = retrieve_nosec_lines(path)

initialize_constraint_table(cfg_list)
log.info("Analysing")
analyse(cfg_list)
log.info("Finding vulnerabilities")
vulnerabilities = find_vulnerabilities(
cfg_list,
ui_mode,
args.blackbox_mapping_file,
args.trigger_word_file,
args.interactive,
nosec_lines

@@ -145,9 +152,9 @@ )

if args.json:
json.report(vulnerabilities, args.output_file)
else:
text.report(vulnerabilities, args.output_file)
args.formatter.report(vulnerabilities, args.output_file, not args.only_unsanitised)
has_unsanitized_vulnerabilities = any(not isinstance(v, SanitisedVulnerability) for v in vulnerabilities)
if has_unsanitized_vulnerabilities:
has_unsanitised_vulnerabilities = any(
not isinstance(v, SanitisedVulnerability)
for v in vulnerabilities
)
if has_unsanitised_vulnerabilities:
sys.exit(1)

@@ -154,0 +161,0 @@

import ast
import logging

@@ -33,3 +34,5 @@ from .alias_helper import handle_aliases_in_calls

log = logging.getLogger(__name__)
class ExprVisitor(StmtVisitor):

@@ -56,2 +59,3 @@ def __init__(

self.function_return_stack = list()
self.function_definition_stack = list() # used to avoid recursion
self.module_definitions_stack = list()

@@ -548,2 +552,3 @@ self.prev_nodes_to_avoid = list()

self.function_return_stack.pop()
self.function_definition_stack.pop()

@@ -566,2 +571,5 @@ return self.nodes[-1]

if definition:
if definition in self.function_definition_stack:
log.debug("Recursion encountered in function %s", _id)
return self.add_blackbox_or_builtin_call(node, blackbox=True)
if isinstance(definition.node, ast.ClassDef):

@@ -572,2 +580,3 @@ self.add_blackbox_or_builtin_call(node, blackbox=False)

self.function_return_stack.append(_id)
self.function_definition_stack.append(definition)
return self.process_function(node, definition)

@@ -574,0 +583,0 @@ else:

import ast
import itertools
import logging
import os.path
from pkgutil import iter_modules

@@ -55,3 +57,6 @@ from .alias_helper import (

log = logging.getLogger(__name__)
uninspectable_modules = {module.name for module in iter_modules()} # Don't warn about failing to import these
class StmtVisitor(ast.NodeVisitor):

@@ -433,5 +438,8 @@ def __init__(self, allow_local_directory_imports=True):

label.visit(node)
print('Assignment not properly handled.',
'Could result in not finding a vulnerability.',
'Assignment:', label.result)
log.warn(
'Assignment not properly handled in %s. Could result in not finding a vulnerability.'
'Assignment: %s',
getattr(self, 'filenames', ['?'])[0],
self.label.result,
)
return self.append_node(AssignmentNode(

@@ -670,2 +678,3 @@ label.result,

call_node.right_hand_side_variables = rhs_vars
# Used in get_sink_args
rhs_visitor = RHSVisitor()

@@ -1027,2 +1036,6 @@ rhs_visitor.visit(node)

)
for alias in node.names:
if alias.name not in uninspectable_modules:
log.warn("Cannot inspect module %s", alias.name)
uninspectable_modules.add(alias.name) # Don't repeatedly warn about this
return IgnoredNode()

@@ -1067,2 +1080,5 @@

)
if node.module not in uninspectable_modules:
log.warn("Cannot inspect module %s", node.module)
uninspectable_modules.add(node.module)
return IgnoredNode()

@@ -5,2 +5,3 @@ """This module contains helper function.

import ast
import logging
import os

@@ -10,5 +11,5 @@ import subprocess

from .transformer import AsyncTransformer
from .transformer import PytTransformer
log = logging.getLogger(__name__)
BLACK_LISTED_CALL_NAMES = ['self']

@@ -21,7 +22,6 @@ recursive = False

try:
print('##### Trying to convert file to Python 3. #####')
log.warn('##### Trying to convert %s to Python 3. #####', path)
subprocess.call(['2to3', '-w', path])
except subprocess.SubprocessError:
print('Check if 2to3 is installed. '
'https://docs.python.org/2/library/2to3.html')
log.exception('Check if 2to3 is installed. https://docs.python.org/2/library/2to3.html')
exit(1)

@@ -41,3 +41,3 @@

tree = ast.parse(f.read())
return AsyncTransformer().visit(tree)
return PytTransformer().visit(tree)
except SyntaxError: # pragma: no cover

@@ -44,0 +44,0 @@ global recursive

import ast
class AsyncTransformer(ast.NodeTransformer):
class AsyncTransformer():
"""Converts all async nodes into their synchronous counterparts."""

@@ -19,1 +19,51 @@

return self.visit(ast.With(**node.__dict__))
class ChainedFunctionTransformer():
def visit_chain(self, node, depth=1):
if (
isinstance(node.value, ast.Call) and
isinstance(node.value.func, ast.Attribute) and
isinstance(node.value.func.value, ast.Call)
):
# Node is assignment or return with value like `b.c().d()`
call_node = node.value
# If we want to handle nested functions in future, depth needs fixing
temp_var_id = '__chain_tmp_{}'.format(depth)
# AST tree is from right to left, so d() is the outer Call and b.c() is the inner Call
unvisited_inner_call = ast.Assign(
targets=[ast.Name(id=temp_var_id, ctx=ast.Store())],
value=call_node.func.value,
)
ast.copy_location(unvisited_inner_call, node)
inner_calls = self.visit_chain(unvisited_inner_call, depth + 1)
for inner_call_node in inner_calls:
ast.copy_location(inner_call_node, node)
outer_call = self.generic_visit(type(node)(
value=ast.Call(
func=ast.Attribute(
value=ast.Name(id=temp_var_id, ctx=ast.Load()),
attr=call_node.func.attr,
ctx=ast.Load(),
),
args=call_node.args,
keywords=call_node.keywords,
),
**{field: value for field, value in ast.iter_fields(node) if field != 'value'} # e.g. targets
))
ast.copy_location(outer_call, node)
ast.copy_location(outer_call.value, node)
ast.copy_location(outer_call.value.func, node)
return [*inner_calls, outer_call]
else:
return [self.generic_visit(node)]
def visit_Assign(self, node):
return self.visit_chain(node)
def visit_Return(self, node):
return self.visit_chain(node)
class PytTransformer(AsyncTransformer, ChainedFunctionTransformer, ast.NodeTransformer):
pass
"""This formatter outputs the issues in JSON."""
import json
from datetime import datetime
from ..vulnerabilities.vulnerability_helper import SanitisedVulnerability
def report(
vulnerabilities,
fileobj
fileobj,
print_sanitised,
):

@@ -22,3 +24,6 @@ """

'generated_at': time_string,
'vulnerabilities': [vuln.as_dict() for vuln in vulnerabilities]
'vulnerabilities': [
vuln.as_dict() for vuln in vulnerabilities
if print_sanitised or not isinstance(vuln, SanitisedVulnerability)
]
}

@@ -25,0 +30,0 @@

"""This formatter outputs the issues as plain text."""
from ..vulnerabilities.vulnerability_helper import SanitisedVulnerability

@@ -6,3 +7,4 @@

vulnerabilities,
fileobj
fileobj,
print_sanitised,
):

@@ -15,13 +17,19 @@ """

fileobj: The output file object, which may be sys.stdout
print_sanitised: Print just unsanitised vulnerabilities or sanitised vulnerabilities as well
"""
number_of_vulnerabilities = len(vulnerabilities)
n_vulnerabilities = len(vulnerabilities)
unsanitised_vulnerabilities = [v for v in vulnerabilities if not isinstance(v, SanitisedVulnerability)]
n_unsanitised = len(unsanitised_vulnerabilities)
n_sanitised = n_vulnerabilities - n_unsanitised
heading = "{} vulnerabilit{} found{}{}\n".format(
'No' if n_unsanitised == 0 else n_unsanitised,
'y' if n_unsanitised == 1 else 'ies',
" (plus {} sanitised)".format(n_sanitised) if n_sanitised else "",
':' if n_vulnerabilities else '.',
)
vulnerabilities_to_print = vulnerabilities if print_sanitised else unsanitised_vulnerabilities
with fileobj:
if number_of_vulnerabilities == 0:
fileobj.write('No vulnerabilities found.\n')
elif number_of_vulnerabilities == 1:
fileobj.write('%s vulnerability found:\n' % number_of_vulnerabilities)
else:
fileobj.write('%s vulnerabilities found:\n' % number_of_vulnerabilities)
fileobj.write(heading)
for i, vulnerability in enumerate(vulnerabilities, start=1):
for i, vulnerability in enumerate(vulnerabilities_to_print, start=1):
fileobj.write('Vulnerability {}:\n{}\n\n'.format(i, vulnerability))

@@ -5,3 +5,5 @@ import argparse

from .formatters import json, screen, text
default_blackbox_mapping_file = os.path.join(

@@ -24,4 +26,5 @@ os.path.dirname(__file__),

required_group.add_argument(
'targets', metavar='targets', type=str, nargs='+',
help='source file(s) or directory(s) to be tested'
'targets', metavar='targets', nargs='+',
help='source file(s) or directory(s) to be scanned',
type=str
)

@@ -32,4 +35,8 @@

optional_group = parser.add_argument_group('optional arguments')
optional_group.add_argument(
'-v', '--verbose',
action='count',
help='Increase logging verbosity. Can repeated e.g. -vvv',
)
optional_group.add_argument(
'-a', '--adaptor',

@@ -55,6 +62,6 @@ help='Choose a web framework adaptor: '

optional_group.add_argument(
'-j', '--json',
help='Prints JSON instead of report.',
action='store_true',
default=False
'-t', '--trigger-word-file',
help='Input file with a list of sources and sinks',
type=str,
default=default_trigger_word_file
)

@@ -68,10 +75,10 @@ optional_group.add_argument(

optional_group.add_argument(
'-t', '--trigger-word-file',
help='Input file with a list of sources and sinks',
type=str,
default=default_trigger_word_file
'-i', '--interactive',
help='Will ask you about each blackbox function call in vulnerability chains.',
action='store_true',
default=False
)
optional_group.add_argument(
'-o', '--output',
help='write report to filename',
help='Write report to filename',
dest='output_file',

@@ -86,7 +93,9 @@ action='store',

action='store_true',
help='do not skip lines with # nosec comments'
help='Do not skip lines with # nosec comments'
)
optional_group.add_argument(
'-r', '--recursive', dest='recursive',
action='store_true', help='find and process files in subdirectories'
'-r', '--recursive',
dest='recursive',
action='store_true',
help='Find and process files in subdirectories'
)

@@ -115,25 +124,26 @@ optional_group.add_argument(

)
def _add_print_group(parser):
print_group = parser.add_argument_group('print arguments')
print_group.add_argument(
'-trim', '--trim-reassigned-in',
help='Trims the reassigned list to just the vulnerability chain.',
optional_group.add_argument(
'-u', '--only-unsanitised',
help="Don't print sanitised vulnerabilities.",
action='store_true',
default=True
default=False,
)
print_group.add_argument(
'-i', '--interactive',
help='Will ask you about each blackbox function call in vulnerability chains.',
action='store_true',
default=False
parser.set_defaults(formatter=text)
formatter_group = optional_group.add_mutually_exclusive_group()
formatter_group.add_argument(
'-j', '--json',
help='Prints JSON instead of report.',
action='store_const',
const=json,
dest='formatter',
)
formatter_group.add_argument(
'-s', '--screen',
help='Prints colorful report.',
action='store_const',
const=screen,
dest='formatter',
)
def _check_required_and_mutually_exclusive_args(parser, args):
if args.targets is None:
parser.error('The targets argument is required')
def parse_args(args):

@@ -143,12 +153,12 @@ if len(args) == 0:

parser = argparse.ArgumentParser(prog='python -m pyt')
# Hack to in order to list required args above optional
parser._action_groups.pop()
_add_required_group(parser)
_add_optional_group(parser)
_add_print_group(parser)
args = parser.parse_args(args)
_check_required_and_mutually_exclusive_args(
parser,
args
)
if args.targets is None:
parser.error('The targets argument is required')
return args
from .vulnerabilities import find_vulnerabilities
from .vulnerability_helper import (
get_vulnerabilities_not_in_baseline,
UImode
)
from .vulnerability_helper import get_vulnerabilities_not_in_baseline

@@ -10,4 +7,3 @@

'find_vulnerabilities',
'get_vulnerabilities_not_in_baseline',
'UImode'
'get_vulnerabilities_not_in_baseline'
]

@@ -26,4 +26,3 @@ """Module for finding vulnerabilities based on a definitions file."""

vuln_factory,
VulnerabilityType,
UImode
VulnerabilityType
)

@@ -310,3 +309,3 @@

blackbox_assignments,
ui_mode,
interactive,
vuln_deets

@@ -325,3 +324,3 @@ ):

blackbox_assignments(set[AssignmentNode]): set of blackbox assignments, includes the ReturnNode's of BBorBInode's.
ui_mode(UImode): determines if we interact with the user when we don't already have a blackbox mapping available.
interactive(bool): determines if we ask the user about blackbox functions not in the mapping file.
vuln_deets(dict): vulnerability details.

@@ -343,3 +342,3 @@

return VulnerabilityType.FALSE
elif ui_mode == UImode.INTERACTIVE:
elif interactive:
user_says = input(

@@ -385,3 +384,3 @@ 'Is the return value of {} with tainted argument "{}" vulnerable? (Y/n)'.format(

cfg,
ui_mode,
interactive,
blackbox_mapping

@@ -403,3 +402,3 @@ ):

cfg(CFG): .blackbox_assignments used in is_unknown, .nodes used in build_def_use_chain
ui_mode(UImode): determines if we interact with the user or trim the nodes in the output, if at all.
interactive(bool): determines if we ask the user about blackbox functions not in the mapping file.
blackbox_mapping(dict): A map of blackbox functions containing whether or not they propagate taint.

@@ -430,4 +429,3 @@

'sink': sink.cfg_node,
'sink_trigger_word': sink.trigger_word,
'reassignment_nodes': source.secondary_nodes
'sink_trigger_word': sink.trigger_word
}

@@ -460,3 +458,3 @@

cfg.blackbox_assignments,
ui_mode,
interactive,
vuln_deets

@@ -467,4 +465,3 @@ )

if ui_mode != UImode.NORMAL:
vuln_deets['reassignment_nodes'] = chain
vuln_deets['reassignment_nodes'] = chain

@@ -480,5 +477,5 @@ return vuln_factory(vulnerability_type)(**vuln_deets)

lattice,
ui_mode,
blackbox_mapping,
vulnerabilities_list,
interactive,
nosec_lines

@@ -492,6 +489,5 @@ ):

lattice(Lattice): the lattice we're analysing.
ui_mode(UImode): determines if we interact with the user or trim the nodes in the output, if at all.
blackbox_mapping(dict): A map of blackbox functions containing whether or not they propagate taint.
vulnerabilities_list(list): That we append to when we find vulnerabilities.
nosec_lines(dict): filenames mapped to their nosec lines
interactive(bool): determines if we ask the user about blackbox functions not in the mapping file.
"""

@@ -513,3 +509,3 @@ triggers = identify_triggers(

cfg,
ui_mode,
interactive,
blackbox_mapping

@@ -523,5 +519,5 @@ )

cfg_list,
ui_mode,
blackbox_mapping_file,
sources_and_sinks_file,
interactive=False,
nosec_lines=defaultdict(set)

@@ -533,7 +529,5 @@ ):

cfg_list(list[CFG]): the list of CFGs to scan.
ui_mode(UImode): determines if we interact with the user or trim the nodes in the output, if at all.
blackbox_mapping_file(str)
sources_and_sinks_file(str)
nosec_lines(dict): filenames mapped to their nosec lines
interactive(bool): determines if we ask the user about blackbox functions not in the mapping file.
Returns:

@@ -552,9 +546,9 @@ A list of vulnerabilities.

Lattice(cfg.nodes),
ui_mode,
blackbox_mapping,
vulnerabilities,
interactive,
nosec_lines
)
if ui_mode == UImode.INTERACTIVE:
if interactive:
with open(blackbox_mapping_file, 'w') as outfile:

@@ -561,0 +555,0 @@ json.dump(blackbox_mapping, outfile, indent=4)

@@ -6,3 +6,2 @@ """This module contains vulnerability types, Enums, nodes and helpers."""

from collections import namedtuple
from itertools import takewhile

@@ -19,8 +18,2 @@ from ..core.node_types import YieldNode

class UImode(Enum):
INTERACTIVE = 0
NORMAL = 1
TRIM = 2
def vuln_factory(vulnerability_type):

@@ -62,7 +55,3 @@ if vulnerability_type == VulnerabilityType.UNKNOWN:

# Remove the sink node and all nodes after the sink from the list of reassignments.
self.reassignment_nodes = list(takewhile(
lambda node: node is not sink,
reassignment_nodes
))
self.reassignment_nodes = reassignment_nodes
self._remove_non_propagating_yields()

@@ -69,0 +58,0 @@

"""A generic framework adaptor that leaves route criteria to the caller."""
import ast
import logging

@@ -13,3 +14,5 @@ from ..cfg import make_cfg

log = logging.getLogger(__name__)
class FrameworkAdaptor():

@@ -35,2 +38,3 @@ """An engine that uses the template pattern to find all

"""Build a function cfg and return it, with all arguments tainted."""
log.debug("Getting CFG for %s", definition.name)
func_cfg = make_cfg(

@@ -37,0 +41,0 @@ definition.node,

Metadata-Version: 1.1
Name: python-taint
Version: 0.39
Version: 0.40
Summary: Find security vulnerabilities in Python web applications using static analysis.

@@ -9,4 +9,3 @@ Home-page: https://github.com/python-security/pyt

License: GPLv2
Download-URL: https://github.com/python-security/pyt/archive/0.39.tar.gz
Description-Content-Type: UNKNOWN
Download-URL: https://github.com/python-security/pyt/archive/0.40.tar.gz
Description: Check out PyT on `GitHub <https://github.com/python-security/pyt>`_!

@@ -13,0 +12,0 @@ Keywords: security,vulnerability,web,flask,django,static-analysis,program-analysis

@@ -29,2 +29,3 @@ MANIFEST.in

pyt/formatters/json.py
pyt/formatters/screen.py
pyt/formatters/text.py

@@ -31,0 +32,0 @@ pyt/helper_visitors/__init__.py

@@ -89,49 +89,52 @@ .. image:: https://travis-ci.org/python-security/pyt.svg?branch=master

usage: python -m pyt [-h] [-a ADAPTOR] [-pr PROJECT_ROOT]
[-b BASELINE_JSON_FILE] [-j] [-m BLACKBOX_MAPPING_FILE]
[-t TRIGGER_WORD_FILE] [-o OUTPUT_FILE] [--ignore-nosec]
[-r] [-x EXCLUDED_PATHS] [-trim] [-i]
targets [targets ...]
[-b BASELINE_JSON_FILE] [-j] [-t TRIGGER_WORD_FILE]
[-m BLACKBOX_MAPPING_FILE] [-i] [-o OUTPUT_FILE]
[--ignore-nosec] [-r] [-x EXCLUDED_PATHS]
[--dont-prepend-root] [--no-local-imports]
targets [targets ...]
required arguments:
targets source file(s) or directory(s) to be tested
targets source file(s) or directory(s) to be scanned
important optional arguments:
-a ADAPTOR, --adaptor ADAPTOR
Choose a web framework adaptor: Flask(Default),
Django, Every or Pylons
Choose a web framework adaptor: Flask(Default),
Django, Every or Pylons
-t TRIGGER_WORD_FILE, --trigger-word-file TRIGGER_WORD_FILE
Input file with a list of sources and sinks
Input file with a list of sources and sinks
-m BLACKBOX_MAPPING_FILE, --blackbox-mapping-file BLACKBOX_MAPPING_FILE
Input blackbox mapping file
Input blackbox mapping file
optional arguments:
-pr PROJECT_ROOT, --project-root PROJECT_ROOT
Add project root, only important when the entry file
is not at the root of the project
Add project root, only important when the entry file
is not at the root of the project.
-b BASELINE_JSON_FILE, --baseline BASELINE_JSON_FILE
Path of a baseline report to compare against (only
JSON-formatted files are accepted)
Path of a baseline report to compare against (only
JSON-formatted files are accepted)
-j, --json Prints JSON instead of report
-j, --json Prints JSON instead of report.
-i, --interactive Will ask you about each blackbox function call in
vulnerability chains.
-o OUTPUT_FILE, --output OUTPUT_FILE
Write report to filename
Write report to filename
--ignore-nosec Do not skip lines with # nosec comments
--ignore-nosec Do not skip lines with # nosec comments
-r, --recursive Find and process files in subdirectories
-r, --recursive Find and process files in subdirectories
-x EXCLUDED_PATHS, --exclude EXCLUDED_PATHS
Separate files with commas
Separate files with commas
--dont-prepend-root In project root e.g. /app, imports are not prepended
with app.*
print arguments:
-trim, --trim-reassigned-in
Trims the reassigned list to just the vulnerability
chain.
-i, --interactive Will ask you about each blackbox function call in
vulnerability chains.
--no-local-imports If set, absolute imports must be relative to the
project root. If not set, modules in the same
directory can be imported just by their names.

@@ -138,0 +141,0 @@ Usage from Source

@@ -5,4 +5,5 @@ [metadata]

[egg_info]
tag_svn_revision = 0
tag_date = 0
tag_build =
tag_date = 0

@@ -5,3 +5,3 @@ from setuptools import find_packages

VERSION = '0.39'
VERSION = '0.40'

@@ -8,0 +8,0 @@