Skip to content

Commit 0e8eb6f

Browse files
committed
refactor: remove backend JWT scanner, APK scanner, and their API/bot/frontend integrations
Remove JWT scanner (internal/scanner/jwt/, internal/tools/jwthack/) - Delete backend JWT hacking engine, scanner module, CLI command - Remove POST /scan/jwt API route and scanJWT handler - Remove Discord jwt_scan command, dispatch, result retrieval, help text - Remove JWT from dashboard launcher, scans-page, r2-prefixes Remove APK scanner (internal/scanner/apkx/, internal/db/apk_cache.go) - Delete APK scanner, downloader, cache DB layer - Remove POST /scan/apkx API route and scanApkX handler - Remove filterApkx(), recoverAPKRescanInput(), parseAPKStructuredLine() - Remove APK-specific JSON walk parsing, isAPKScan result rendering - Remove Discord apkx_scan/package/ios commands and handler - Remove APK from DB schema (apk_cache table) - Remove APK directory preservation in subdomain cleanup - Remove APK from scope keywords, R2 content types, FindCachedVersion - Remove APK from dashboard launcher, scans-page, module-registry, scan-common, scan-detail, r2-prefixes, app-config-state Client-side tools preserved: Security Lab JWT Analyzer, APK Auditor SPA
1 parent 64bcf57 commit 0e8eb6f

26 files changed

Lines changed: 9 additions & 2541 deletions

internal/api/api.go

Lines changed: 0 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -583,9 +583,7 @@ func SetupAPI() *gin.Engine {
583583
api.POST("/backup", scanBackup) // Backup file discovery
584584
api.POST("/misconfig", scanMisconfig) // Cloud misconfiguration scan
585585
api.POST("/zerodays", scanZerodays) // Zerodays scan (CVE-2025-55182 React2Shell, CVE-2025-14847 MongoDB)
586-
api.POST("/jwt", scanJWT) // JWT vulnerability scan
587586
api.POST("/asr", scanASR) // Attack Surface Reduction scan
588-
api.POST("/apkx", scanApkX) // APK analysis and MITM patching
589587
api.GET("/:scan_id/status", getScanStatus)
590588
api.GET("/:scan_id/results", getScanResults)
591589
api.GET("/:scan_id/download", downloadScanResults)
@@ -1058,11 +1056,6 @@ func docsHandler(c *gin.Context) {
10581056
<div class="description">Zerodays scan (CVE-2025-55182 React2Shell, CVE-2025-14847 MongoDB)</div>
10591057
</div>
10601058
1061-
<div class="endpoint">
1062-
<div class="endpoint-path"><span class="method post">POST</span> /scan/jwt</div>
1063-
<div class="description">JWT vulnerability scan</div>
1064-
</div>
1065-
10661059
<div class="endpoint">
10671060
<div class="endpoint-path"><span class="method get">GET</span> /scan/:scan_id/status</div>
10681061
<div class="description">Get scan status by scan ID</div>
@@ -1273,8 +1266,6 @@ func generateScanID() string {
12731266
}
12741267

12751268
// extractScanTargetFromCommand infers the human-readable target from command arguments (#11).
1276-
// Special cases:
1277-
// - JWT scans: returns "jwt-token" rather than exposing the actual token value in the DB.
12781269
func extractScanTargetFromCommand(command []string, scanType string) string {
12791270
if len(command) == 0 {
12801271
return ""
@@ -1308,9 +1299,6 @@ func extractScanTargetFromCommand(command []string, scanType string) string {
13081299
return next
13091300
case st == "zerodays" && arg == "-f":
13101301
return "file:" + filepath.Base(next)
1311-
case st == "jwt" && (arg == "-t" || arg == "--token"):
1312-
// Never expose the raw token string in the DB.
1313-
return "jwt-token"
13141302
}
13151303
}
13161304
return ""
@@ -1505,7 +1493,6 @@ func executeScan(scanID string, command []string, scanType string) {
15051493
"dns_cf1016": "CF1016 Dangling DNS", "dns-cf1016": "CF1016 Dangling DNS",
15061494
"misconfig": "Misconfiguration", "s3": "S3 Bucket",
15071495
"github": "GitHub Recon", "github_org": "GitHub Org Recon",
1508-
"jwt": "JWT Scan",
15091496
"dns-takeover": "DNS Takeover", "dns-dangling-ip": "Dangling IP",
15101497
"nuclei": "Nuclei Scan", "tech": "Tech Detection",
15111498
"ports": "Port Scan", "gf": "GF Patterns",
@@ -1643,12 +1630,6 @@ func indexScanArtifacts(scanID, scanType, target string) {
16431630
if target != "" {
16441631
roots = append(roots, filepath.Join(resultsDir, "github", "orgs", target))
16451632
}
1646-
case "jwt":
1647-
roots = append(roots, filepath.Join(resultsDir, "jwt-scan"))
1648-
case "apkx":
1649-
if target != "" {
1650-
roots = append(roots, filepath.Join(resultsDir, "apkx", target))
1651-
}
16521633
// DNS-specific scans: only index from their specific output dir, never the whole domain root.
16531634
case "dns-takeover", "dns-dangling-ip":
16541635
if target != "" {
@@ -1682,18 +1663,6 @@ func indexScanArtifacts(scanID, scanType, target string) {
16821663
if shouldSkipArtifact(path) {
16831664
return nil
16841665
}
1685-
if scanType == "apkx" {
1686-
baseName := filepath.Base(path)
1687-
isPatched := strings.HasSuffix(baseName, "-mitm.apk")
1688-
isMainApk := strings.HasSuffix(baseName, ".apk") &&
1689-
!strings.HasPrefix(baseName, "config.") &&
1690-
!strings.Contains(baseName, "-unsigned") &&
1691-
!strings.Contains(baseName, "-aligned")
1692-
1693-
if !isPatched && !isMainApk {
1694-
return nil
1695-
}
1696-
}
16971666
if _, ok := seen[path]; ok {
16981667
return nil
16991668
}

internal/api/scan_handlers.go

Lines changed: 0 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ import (
1818
"time"
1919

2020
"github.com/gin-gonic/gin"
21-
apkxmod "github.com/h0tak88r/AutoAR/internal/scanner/apkx"
2221
asrmod "github.com/h0tak88r/AutoAR/internal/scanner/asr"
2322
backupmod "github.com/h0tak88r/AutoAR/internal/scanner/backup"
2423
cf1016mod "github.com/h0tak88r/AutoAR/internal/scanner/cf1016"
@@ -651,36 +650,6 @@ func scanASR(c *gin.Context) {
651650
okStarted(c, scanID, fmt.Sprintf("ASR scan started for %s", domain))
652651
}
653652

654-
// ── JWT ───────────────────────────────────────────────────────────────────────
655-
// JWT uses an external binary; keep subprocess but avoid forking autoar itself.
656-
657-
func scanJWT(c *gin.Context) {
658-
var req ScanRequest
659-
if !bindOrBad(c, &req) {
660-
return
661-
}
662-
if !requireField(c, req.Token, "JWT token") {
663-
return
664-
}
665-
token := *req.Token
666-
scanID := generateScanID()
667-
command := []string{utils.GetAutoarScriptPath(), "jwt", "scan", "-t", token}
668-
if req.SkipCrack != nil && *req.SkipCrack {
669-
command = append(command, "--skip-crack")
670-
}
671-
if req.SkipPayloads != nil && *req.SkipPayloads {
672-
command = append(command, "--skip-payloads")
673-
}
674-
if req.WordlistPath != nil && *req.WordlistPath != "" {
675-
command = append(command, "--wordlist", *req.WordlistPath)
676-
}
677-
if req.MaxCrackAttempts != nil && *req.MaxCrackAttempts > 0 {
678-
command = append(command, "--max-crack-attempts", fmt.Sprintf("%d", *req.MaxCrackAttempts))
679-
}
680-
go executeScan(scanID, command, "jwt")
681-
okStarted(c, scanID, "JWT vulnerability scan started")
682-
}
683-
684653
// ── S3 ────────────────────────────────────────────────────────────────────────
685654

686655
func scanS3(c *gin.Context) {
@@ -772,44 +741,6 @@ func scanGitHubOrg(c *gin.Context) {
772741
okStarted(c, scanID, fmt.Sprintf("GitHub organization scan started for %s", org))
773742
}
774743

775-
// ── APK/X APK analysis ───────────────────────────────────────────────
776-
777-
func scanApkX(c *gin.Context) {
778-
var req ScanRequest
779-
if !bindOrBad(c, &req) {
780-
return
781-
}
782-
783-
// Support both file path (if uploaded via /api/upload) or package name
784-
var target string
785-
if req.PackageID != nil && *req.PackageID != "" {
786-
target = *req.PackageID
787-
} else if req.FilePath != nil && *req.FilePath != "" {
788-
target = *req.FilePath
789-
} else {
790-
c.JSON(http.StatusBadRequest, gin.H{"error": "Either package_id or file_path (for uploaded APK) is required"})
791-
return
792-
}
793-
794-
mitm := req.MITM != nil && *req.MITM
795-
scanID := generateScanID()
796-
797-
go RunScanInProcess(scanID, "apkx", target, func() error {
798-
opts := apkxmod.Options{
799-
MITM: mitm,
800-
}
801-
if req.PackageID != nil && *req.PackageID != "" {
802-
opts.Package = target
803-
} else {
804-
opts.InputPath = target
805-
}
806-
_, err := apkxmod.Run(opts)
807-
return err
808-
})
809-
810-
okStarted(c, scanID, fmt.Sprintf("APK analysis (apkX) started for %s", target))
811-
}
812-
813744
// ── Keyhack ───────────────────────────────────────────────────────────────────
814745
// Keyhack uses an external binary; delegated to executeScan.
815746

internal/api/scan_results_api.go

Lines changed: 2 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -377,9 +377,6 @@ func paginateFileEntries(entries []fileEntry, page, perPage int) (pageItems []fi
377377

378378
func inferModuleFromFileName(name string) string {
379379
n := strings.ToLower(strings.TrimSpace(name))
380-
if strings.Contains(n, "/apkx/") || strings.Contains(n, "\\apkx\\") {
381-
return "apkx"
382-
}
383380
switch {
384381
case strings.Contains(n, "cf1016") || strings.Contains(n, "cf-1016") || strings.Contains(n, "cloudflare-1016"):
385382
return "cf1016"
@@ -405,8 +402,6 @@ func inferModuleFromFileName(name string) string {
405402
return "github-scan"
406403
case strings.Contains(n, "js-secret") || strings.Contains(n, "js-exposure") || strings.Contains(n, "secret"):
407404
return "js-analysis"
408-
case strings.Contains(n, "apk") || strings.Contains(n, "androidmanifest") || strings.Contains(n, "jadx") || strings.Contains(n, "dex"):
409-
return "apkx"
410405
case strings.HasPrefix(n, "gf-") || strings.Contains(n, "gf-"):
411406
return "gf-patterns"
412407
case strings.Contains(n, "misconfig"):
@@ -1087,43 +1082,13 @@ func normalizeUnifiedContractRow(r parsedFinding) parsedFinding {
10871082
return r
10881083
}
10891084

1090-
func parseAPKStructuredLine(line string) (path, matcher, ctx string) {
1091-
s := strings.TrimSpace(line)
1092-
if s == "" {
1093-
return "", "", ""
1094-
}
1095-
// Typical format: "<path>: <matcher> (Context: ...)".
1096-
// Some scanners emit ":" without a trailing space, so accept both.
1097-
if idx := strings.Index(s, ":"); idx > 0 && idx < len(s)-1 {
1098-
left := strings.TrimSpace(s[:idx])
1099-
right := strings.TrimSpace(s[idx+1:])
1100-
if strings.Contains(left, "/") || strings.Contains(left, "\\") || strings.Contains(left, ".") {
1101-
path = left
1102-
matcher = right
1103-
}
1104-
}
1105-
if path == "" {
1106-
matcher = s
1107-
}
1108-
if i := strings.LastIndex(strings.ToLower(matcher), "(context:"); i >= 0 {
1109-
ctx = strings.TrimSpace(matcher[i+len("(context:"):])
1110-
ctx = strings.TrimSuffix(ctx, ")")
1111-
matcher = strings.TrimSpace(matcher[:i])
1112-
}
1113-
return path, matcher, ctx
1114-
}
1115-
1116-
11171085
// inferReconKind maps artifact filenames to a stable dataset key for unified recon tables.
11181086
func inferReconKind(fileName string) string {
11191087
full := strings.ToLower(strings.TrimSpace(fileName))
11201088
b := strings.ToLower(filepath.Base(full))
11211089
if b == "" {
11221090
return "other"
11231091
}
1124-
if strings.Contains(full, "/apkx/") || strings.Contains(full, "\\apkx\\") {
1125-
return "apkx"
1126-
}
11271092
switch {
11281093
// GitHub secret findings (dashboard tabs + filters)
11291094
case strings.Contains(b, "github-secret") || strings.Contains(b, "github-secrets"):
@@ -1182,9 +1147,6 @@ func inferReconKind(fileName string) string {
11821147
// Backup
11831148
case strings.Contains(b, "backup") || strings.Contains(b, "fuzzuli"):
11841149
return "backup"
1185-
// APK analysis
1186-
case strings.Contains(b, "apk") || strings.Contains(b, "androidmanifest") || strings.Contains(b, "jadx") || strings.Contains(b, "dex"):
1187-
return "apkx"
11881150
// Ports
11891151
case strings.Contains(b, "port-scan") || strings.Contains(b, "ports") || strings.Contains(b, "nmap") || strings.Contains(b, "masscan"):
11901152
return "ports"
@@ -1663,88 +1625,8 @@ func parseArtifactFindings(raw []byte, module, category string, maxRows int) []p
16631625
return
16641626
}
16651627
switch t := x.(type) {
1666-
case map[string]interface{}:
1667-
if strings.EqualFold(strings.TrimSpace(module), "apkx") {
1668-
// apkx results.json is typically map[string][]string where each key is
1669-
// a category and each array item is one finding line. It can also
1670-
// contain scalar metadata fields (package_name, version, etc.).
1671-
keys := make([]string, 0, len(t))
1672-
for k := range t {
1673-
keys = append(keys, k)
1674-
}
1675-
sort.Strings(keys)
1676-
for _, k := range keys {
1677-
if len(out) >= maxRows {
1678-
return
1679-
}
1680-
switch vv := t[k].(type) {
1681-
case []interface{}:
1682-
for _, it := range vv {
1683-
if len(out) >= maxRows {
1684-
return
1685-
}
1686-
line := strings.TrimSpace(fmt.Sprint(it))
1687-
if line == "" || line == "<nil>" {
1688-
continue
1689-
}
1690-
p, mv, cx := parseAPKStructuredLine(line)
1691-
appendRow(parsedFinding{
1692-
Severity: "info",
1693-
Target: k,
1694-
Finding: line,
1695-
Path: p,
1696-
CategoryName: k,
1697-
MatcherValue: mv,
1698-
Context: cx,
1699-
})
1700-
}
1701-
case string:
1702-
line := strings.TrimSpace(vv)
1703-
if line == "" || line == "<nil>" {
1704-
continue
1705-
}
1706-
p, mv, cx := parseAPKStructuredLine(line)
1707-
appendRow(parsedFinding{
1708-
Severity: "info",
1709-
Target: k,
1710-
Finding: line,
1711-
Path: p,
1712-
CategoryName: k,
1713-
MatcherValue: mv,
1714-
Context: cx,
1715-
})
1716-
case float64, bool, int, int64, uint64:
1717-
line := strings.TrimSpace(fmt.Sprint(vv))
1718-
if line == "" || line == "<nil>" {
1719-
continue
1720-
}
1721-
appendRow(parsedFinding{
1722-
Severity: "info",
1723-
Target: k,
1724-
Finding: line,
1725-
CategoryName: k,
1726-
MatcherValue: line,
1727-
})
1728-
case map[string]interface{}:
1729-
if enc, encErr := json.Marshal(vv); encErr == nil {
1730-
line := strings.TrimSpace(string(enc))
1731-
if line != "" && line != "{}" {
1732-
appendRow(parsedFinding{
1733-
Severity: "info",
1734-
Target: k,
1735-
Finding: line,
1736-
CategoryName: k,
1737-
MatcherValue: line,
1738-
})
1739-
}
1740-
}
1741-
}
1742-
}
1743-
if len(out) > 0 {
1744-
return
1745-
}
1746-
}
1747-
// ZeroDays summary-only guard: TotalVulnerable==0 with no findings -> skip.
1628+
case map[string]interface{}:
1629+
// ZeroDays summary-only guard: TotalVulnerable==0 with no findings -> skip.
17481630
if tv, hasTV := t["TotalVulnerable"]; hasTV {
17491631
if n, ok := tv.(float64); ok && n == 0 {
17501632
return
@@ -1901,7 +1783,6 @@ func apiScanParsedResults(c *gin.Context) {
19011783
return
19021784
}
19031785
scanType := strings.ToLower(strings.TrimSpace(scanRec.ScanType))
1904-
isAPKScan := strings.Contains(scanType, "apkx")
19051786

19061787
section := strings.ToLower(strings.TrimSpace(c.DefaultQuery("section", "all")))
19071788
limit, _ := strconv.Atoi(c.DefaultQuery("limit", "1200"))
@@ -1924,32 +1805,10 @@ func apiScanParsedResults(c *gin.Context) {
19241805
kind := inferReconKind(e.FileName) // always attach kind for unified table tabs
19251806
module := e.Module
19261807
category := e.Category
1927-
if isAPKScan {
1928-
// APK scans commonly produce generic file names (e.g., results.json/report.html).
1929-
// Keep APK findings grouped in APK Analysis instead of falling back to autoar/other.
1930-
if module == "" || module == "autoar" || module == "unknown" || module == "github-scan" {
1931-
module = "apkx"
1932-
}
1933-
if category == "" || category == "output" || category == "recon" {
1934-
category = "vulnerability"
1935-
}
1936-
if kind == "" || kind == "other" || kind == "vuln" {
1937-
kind = "apkx"
1938-
}
1939-
}
19401808
for _, r := range ps {
19411809
if len(rows) >= limit {
19421810
return
19431811
}
1944-
if isAPKScan {
1945-
// Drop placeholder rows produced by summary objects with no concrete finding fields.
1946-
f := strings.ToLower(strings.TrimSpace(r.Finding))
1947-
t := strings.TrimSpace(r.Target)
1948-
if (f == "" || f == "—" || f == "autoar" || f == "apkx") &&
1949-
(t == "" || t == "—" || t == "-") {
1950-
continue
1951-
}
1952-
}
19531812
r.File = e.FileName
19541813
r.Module = module
19551814
r.Category = category
@@ -1966,16 +1825,6 @@ func apiScanParsedResults(c *gin.Context) {
19661825
for _, e := range entries {
19671826
presentFiles[strings.ToLower(e.FileName)] = true
19681827
}
1969-
hasApkxFindingsJSON := false
1970-
if isAPKScan {
1971-
for _, e := range entries {
1972-
n := strings.ToLower(strings.TrimSpace(e.FileName))
1973-
if n == "results.json" || strings.Contains(n, "vulnerabilities") || strings.Contains(n, "findings") {
1974-
hasApkxFindingsJSON = true
1975-
break
1976-
}
1977-
}
1978-
}
19791828
// rawToJSON maps a raw shadowed filename to the JSON that supersedes it.
19801829
// Also maps pipeline input files (subdomains/URLs) to a sentinel "" to mark
19811830
// them as "always skip" — the sentinel is never present so they are dropped.

0 commit comments

Comments
 (0)