Skip to content

Commit 3887ebb

Browse files
committed
updates
1 parent b15f8d9 commit 3887ebb

9 files changed

Lines changed: 64 additions & 153 deletions

File tree

docs/astlines.md

Lines changed: 0 additions & 111 deletions
This file was deleted.

docs/astlines2.md

Lines changed: 0 additions & 26 deletions
This file was deleted.

docs/cimode.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ If needed, you can also export the `json` output for further processing in a sep
7171
### HTML report example
7272

7373

74-
```yml
74+
```yaml
7575
# SAST scan with Python Code Audit on GitLab.com
7676
image: python:3.13-slim
7777

@@ -137,7 +137,7 @@ codeaudit-scan:
137137
138138
For structured processing or integration with other tools:
139139
140-
```yml
140+
```yaml
141141
codeaudit-scan:
142142
stage: scan
143143

docs/examples/codeauditchecks.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -762,4 +762,4 @@
762762
<td>Vulnerable to path traversal attacks if used with untrusted archives.</td>
763763
</tr>
764764
</tbody>
765-
</table><br><p>Number of implemented security validations:<b>87</b></p><p>Version of codeaudit: <b>1.7.0</b><p>Because Python and cybersecurity are constantly changing, issue reports <b>SHOULD</b> specify the codeaudit version used.</p><p><b>Disclaimer:</b> <i>This SAST tool <a href="https://github.com/nocomplexity/codeaudit" target="_blank"><b>Python Code Audit</b></a> provides a powerful, automatic security analysis for Python source code. However, it's not a substitute for human review in combination with business knowledge. Undetected vulnerabilities may still exist.</i></p><p>This Python security report was created on: <b>2026-06-22 11:05</b> with <a href="https://github.com/nocomplexity/codeaudit" target="_blank"><b>Python Code Audit</b></a> version <b>1.7.0</b></p><hr><footer><div class="footer-links">Check the <a href="https://nocomplexity.com/documents/codeaudit/intro.html" target="_blank">documentation</a> for help on found issues.<br>Codeaudit is made with <span class="heart">&#10084;</span> by cyber security professionals who advocate for <a href="https://nocomplexity.com/simplify-security/" target="_blank">open simple security solutions</a>.<br><a href="https://nocomplexity.com/documents/codeaudit/CONTRIBUTE.html" target="_blank">Join the community</a> and contribute to make this tool better!</div></footer></div></body></html>
765+
</table><br><p>Number of implemented security validations:<b>87</b></p><p>Version of codeaudit: <b>1.7.0</b><p>Because Python and cybersecurity are constantly changing, issue reports <b>SHOULD</b> specify the codeaudit version used.</p><p><b>Disclaimer:</b> <i>This SAST tool <a href="https://github.com/nocomplexity/codeaudit" target="_blank"><b>Python Code Audit</b></a> provides a powerful, automatic security analysis for Python source code. However, it's not a substitute for human review in combination with business knowledge. Undetected vulnerabilities may still exist.</i></p><p>This Python security report was created on: <b>2026-06-24 17:16</b> with <a href="https://github.com/nocomplexity/codeaudit" target="_blank"><b>Python Code Audit</b></a> version <b>1.7.0</b></p><hr><footer><div class="footer-links">Check the <a href="https://nocomplexity.com/documents/codeaudit/intro.html" target="_blank">documentation</a> for help on found issues.<br>Codeaudit is made with <span class="heart">&#10084;</span> by cyber security professionals who advocate for <a href="https://nocomplexity.com/simplify-security/" target="_blank">open simple security solutions</a>.<br><a href="https://nocomplexity.com/documents/codeaudit/CONTRIBUTE.html" target="_blank">Join the community</a> and contribute to make this tool better!</div></footer></div></body></html>

docs/examples/demoscan.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "Python_Code_Audit",
33
"version": "1.7.0",
4-
"generated_on": "2026-06-22 11:04",
4+
"generated_on": "2026-06-24 17:16",
55
"file_security_info": {
66
"0": {
77
"FileName": "demofile.py",

src/codeaudit/api_interfaces.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,22 @@ def get_weakness_counts(input_file, nosec=False):
311311

312312

313313
def get_modules(filename):
314-
"""Gets modules of a Python file"""
314+
"""Extract imported modules from a Python source file.
315+
316+
Analyzes the specified Python file and returns the modules imported
317+
directly within the source code. This approach relies on the actual
318+
imports present in the file rather than dependency declarations such as
319+
``requirements.txt`` or ``pyproject.toml``, which may be incomplete or
320+
outdated.
321+
322+
Args:
323+
filename (str): Path to the Python file to analyze.
324+
325+
Returns:
326+
dict: A dictionary containing discovered modules. Expected keys are:
327+
- ``core_modules`` (list[str]): Standard library modules.
328+
- ``imported_modules`` (list[str]): Third-party modules.
329+
"""
315330
modules_found = get_imported_modules_by_file(filename)
316331
return modules_found
317332

@@ -731,7 +746,7 @@ def _collect_issue_lines(filename, line, context=1):
731746

732747
snippet_lines = [l.rstrip("\n") for l in snippet_lines if l.strip() != ""]
733748

734-
# Escape HTML to prevent injection
749+
# Escape HTML to prevent HTML injection
735750
escaped_lines = [html.escape(l) for l in snippet_lines]
736751

737752
code_lines = (

src/codeaudit/reporting.py

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,6 @@
4646
get_imported_modules,
4747
check_module_vulnerability,
4848
get_all_modules,
49-
get_imported_modules_by_file,
5049
)
5150
from codeaudit.htmlhelpfunctions import json_to_html, dict_list_to_html_table
5251

@@ -59,7 +58,7 @@
5958

6059
from codeaudit.privacy_lint import data_egress_scan, has_privacy_findings
6160
from codeaudit.suppression import filter_sast_results
62-
from codeaudit.api_interfaces import _collect_issue_lines
61+
from codeaudit.api_interfaces import _collect_issue_lines, get_modules
6362

6463
CA_VERSION = __version__
6564

@@ -229,7 +228,7 @@ def display_found_modules(modules_discovered):
229228
"""
230229
core_modules = modules_discovered["core_modules"]
231230
external_modules = modules_discovered["imported_modules"]
232-
output = "<p><b>Used Python Standard libraries:</b></p>"
231+
output = "<p><b>Used Python Standard Libraries:</b></p>"
233232
output += (
234233
"<ul>\n"
235234
+ "\n".join(f" <li>{module}</li>" for module in core_modules)
@@ -512,7 +511,6 @@ def single_file_report(filename, scan_output):
512511
] # reorder the columns before converting to html
513512
df = df.sort_values(by="line") # sort by line number
514513
if number_of_issues > 0:
515-
# output = f'<p>&#9888;&#65039; <b>{number_of_issues}</b> potential <b>security issues</b> found!</p>'
516514
output = f'<p>&#9888;&#65039; <b>{number_of_issues}</b> potential <b>security issue{"s" if number_of_issues != 1 else ""}</b> found!</p>'
517515
output += "<details>"
518516
output += "<summary>View identified security weaknesses.</summary>"
@@ -530,12 +528,18 @@ def single_file_report(filename, scan_output):
530528
output += df_overview.to_html(escape=True, index=False)
531529
output += "</details>"
532530
output += "<br>"
533-
output += "<details>"
534-
output += "<summary>View used modules in this file.</summary>"
535-
modules_found = get_imported_modules_by_file(filename)
536-
output += display_found_modules(modules_found)
537-
output += f'<p>To check for <b>reported vulnerabilities</b> in external modules used by this file, use the command:<br><div class="code-box">codeaudit modulescan {filename}</div><br></p>'
538-
output += "</details>"
531+
modules_found = get_modules(filename)
532+
if any(modules_found.values()):
533+
output += "<details>"
534+
output += "<summary>View used modules in this file.</summary>"
535+
output += display_found_modules(modules_found)
536+
if modules_found and modules_found.get(
537+
"imported_modules"
538+
): # only display when external modules are found
539+
output += f'<p>To check for <b>reported vulnerabilities</b> in external modules used by this file, use the command:<br><div class="code-box">codeaudit modulescan {filename}</div><br></p>'
540+
output += "</details>"
541+
else:
542+
output += "<p>No modules found in this file.</p>"
539543
return output
540544

541545

tests/test_modulecheck.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,22 @@ def test_module_check():
2323
assert actual_data == expected_data
2424

2525

26+
def test_module_notpresent_check():
27+
# No modules present in this file , no PSL , no external modules,
28+
current_file_directory = Path(__file__).parent
29+
# validation1.py is in a subfolder:
30+
validation_file_path = current_file_directory / "validationfiles" / "malware.py"
31+
source = read_in_source_file(validation_file_path)
32+
33+
actual_data = get_imported_modules(source)
34+
35+
# This is the expected dictionary
36+
expected_data = {"core_modules": [], "imported_modules": []}
37+
38+
# Assert that the actual data matches the expected data
39+
assert actual_data == expected_data
40+
41+
2642
def test_module_vulnerability_info():
2743
## note: Output can change if more info is added to OSV!
2844

tests/validationfiles/malware.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Source https://www.stepsecurity.io/blog/forcememo-hundreds-of-github-python-repos-compromised-via-account-takeover-and-force-push
2+
3+
# Obfuscation wrapper (appended to end of legitimate Python file)
4+
# -*- coding: utf-8 -*-
5+
aqgqzxkfjzbdnhz = __import__('base64')
6+
wogyjaaijwqbpxe = __import__('zlib')
7+
idzextbcjbgkdih = 134
8+
qyrrhmmwrhaknyf = lambda d, o: bytes([b ^ idzextbcjbgkdih for b in d])
9+
lzcdrtfxyqiplpd = '<4,800-character base64 blob>'
10+
runzmcxgusiurqv = wogyjaaijwqbpxe.decompress(
11+
aqgqzxkfjzbdnhz.b64decode(lzcdrtfxyqiplpd))
12+
ycqljtcxxkyiplo = qyrrhmmwrhaknyf(runzmcxgusiurqv, idzextbcjbgkdih)
13+
exec(compile(ycqljtcxxkyiplo, '<>', 'exec'))

0 commit comments

Comments
 (0)