Haitao Huang

43 papers A 1B 3C 2Misc 1Journal 24Unranked 12
YearRankTypeTitle / Venue / Authors
2025 J jnl
Inf. Fusion
Siwei Xie, Li Xiao, Haitao Huang, Dayang Chen, Haiman Guo, Amar Jain
2025 J jnl
Comput. Aided Civ. Infrastructure Eng.
Liang He, Haitao Huang, Wentao Zhang, Changjiang Dai, Guannan Li, Alessio Alexiadis, Mengzhe Tao, Wim Van den bergh, Karol J. Kowalski
2025 J jnl
CoRR
Haitao Huang, Chuangtao Chen, Qinglin Zhao
2025 J jnl
IEEE Access
Haitao Huang, Ying Deng, Bowen Hao, Wenguang Liu, Xiaoyu Tu, Guojun Zeng
2025 J jnl
IEEE Access
Yulian Li, Jiyang Gao, Yikang Du, Yuxuan Xiao, Zhengjie Gao, Haitao Huang
2025 conf
ACL (1)
Peng Zhou, Pengsen Ma, Jianmin Wang, Xibao Cai, Haitao Huang, Wei Liu, Longyue Wang, Lai Hou Tim, Xiangxiang Zeng
2025 J jnl
CoRR
Fu Chen, Qinglin Zhao, Li Feng, Longfei Tang, Yangbin Lin, Haitao Huang
2025 J jnl
J. Robotics
Qingyan Li, Haitao Huang, Yulian Li, Qiyou Wu
2024 J jnl
IEEE Trans. Comput. Soc. Syst.
Haitao Huang, Hu Tian, Xiaolong Zheng, Xingwei Zhang, Daniel Dajun Zeng, Fei-Yue Wang
2024 Misc conf
ICASSP
Haitao Huang, Chi-Man Pun, Haolun Li, Mengqi Liu, Jian Xiong, Hao Gao
2024 A conf
ICME
Chuqiao Wu, Haitao Huang, Wenming Yang
2024 J jnl
IEEE Trans. Neural Networks Learn. Syst.
Zhiyong Lv, Haitao Huang, Weiwei Sun, Meng Jia, Jón Atli Benediktsson, Fengrui Chen
2024 J jnl
IEEE Trans. Geosci. Remote. Sens.
Haitao Huang, Baopu Li, Yuchen Zhang, Tao Chen, Bin Wang
2024 conf
BMSB
Haitao Huang, Rongli Jia, Yuhong Zhang, Rong Xie, Li Song, Lin Li, Yanan Feng
2024 J jnl
Multim. Tools Appl.
Jianming Zhang, Haitao Huang, Xiaokang Jin, Li-Dan Kuang, Jin Zhang
2023 J jnl
Remote. Sens.
Junchen Yang, Daohong Wang, Haitao Huang, Ting Wu, Nobuyuki Takagi, Kazuo Yamamoto
2023 conf
CNIOT
Tao Wang, Haitao Huang, Ting Tian, Zhengda Zhou
2023 J jnl
IEEE Access
Haitao Huang, Min-Chul Shin, Jieun Lee, Seung-Hyun Yoon
2023 conf
IoTAAI
Zijing Liang, Zirui Fang, Haitao Huang, Zhiyuan Wang, Yifan Hong, Ke Liu, Penghui Shang
2023 conf
ICAICE
Haitao Huang, Guangming Lu, Fanglin Chen
2023 J jnl
IEEE Geosci. Remote. Sens. Lett.
Zhiyong Lv, Haitao Huang, Weiwei Sun, Tao Lei, Jón Atli Benediktsson, Junhuai Li
2022 J jnl
IEEE Internet Things J.
Qiuhong Wang, Jingjing Gu, Haitao Huang, Yanchao Zhao, Mohsen Guizani
2022 J jnl
IEEE Trans. Wirel. Commun.
Haitao Huang, Deli Qiao, Mustafa Cenk Gursoy
2022 J jnl
Proc. IEEE
Zhiyong Lv, Haitao Huang, Xinghua Li, Minghua Zhao, Jón Atli Benediktsson, Weiwei Sun, Nicola Falco
2022 J jnl
IEEE Geosci. Remote. Sens. Lett.
Zhiyong Lv, Haitao Huang, Lipeng Gao, Jón Atli Benediktsson, Minghua Zhao, Cheng Shi
2021 B conf
CLOUD
Hao Li, Haitao Huang, Zhuzhong Qian
2020 conf
DASFAA (1)
Xinle Wu, Lei Wang, Shuo Wang, Xiaofeng Meng, Linfeng Li, Haitao Huang, Xiaohong Zhang, Jun Yan
2020 J jnl
IT Prof.
Debra P. C. Peters, Heather M. Savoy, Geovany A. Ramírez, Haitao Huang
2020 conf
INFOCOM Workshops
Haitao Huang, Deli Qiao, Mustafa Cenk Gursoy
2020 J jnl
CoRR
Haitao Huang, Deli Qiao, Mustafa Cenk Gursoy
2020 conf
ICITE
Yatao Zhao, Jiangfeng Wang, Sijie Cheng, Zhijun Gao, Haitao Huang
2020 J jnl
BMC Medical Informatics Decis. Mak.
Yang An, Jianlin Wang, Liang Zhang, Hanyu Zhao, Zhan Gao, Haitao Huang, Zhenguang Du, Zengtao Jiao, Jun Yan, Xiaopeng Wei, Bo Jin
2020 conf
DASFAA (3)
Qiao Jin, Haoyang Ding, Linfeng Li, Haitao Huang, Lei Wang, Jun Yan
2019 J jnl
Multim. Tools Appl.
Shengli Song, Haitao Huang, Tongxiao Ruan
2019 conf
MSN
Haitao Huang, Jingjing Gu, Qiuhong Wang, Yi Zhuang
2019 conf
HBAI@IJCAI
Yong Zhang, Jun Yan, Haitao Huang, Christopher Yencha
2019 J jnl
Clust. Comput.
Shengli Song, Nan Zhang, Haitao Huang
2018 B conf
ICPADS
Qiuhong Wang, Jingjing Gu, Haitao Huang, Yanchao Zhao
2018 B conf
ICPR
Haojun Ai, Liezhuo Zhang, Zhiyu Yuan, Haitao Huang
2016 conf
ICDCS Workshops
Xin Shi, Fei Wu, Changsheng Xie, Haitao Huang, Ming Zhu
2004 J jnl
ACM SIGSOFT Softw. Eng. Notes
Guoqing Xu, Zongyuan Yang, Haitao Huang
2004 C conf
APSEC
Guoqing Xu, Zongyuan Yang, Haitao Huang, Qian Chen II, Ling Chen, Fengbin Xu
2004 C conf
APSEC
Guoqing Xu, Zongyuan Yang, Haitao Huang
redb/extractors/js_extractors/js_patterns.py
← Index redb/extractors/js_extractors/js_patterns.py python
"""Canonical, compiled JavaScript regex patterns shared across JS extractors.

All suspicious-API patterns and the few feature-only patterns live here so each
expression is compiled exactly once per Python process and so any pattern that
was previously duplicated across `js_features.py` and `js_suspicious_apis.py`
now resolves to a single shared compiled object.

JavaScript is case-sensitive at runtime, but every suspicious-API pattern matches
either a literal-case identifier (`\\beval\\s*\\(`, `String\\.fromCharCode`, etc.)
or a string-quoted token (`"powershell"`). Compiling them with `re.IGNORECASE`
matches the historical behaviour of `JSSuspiciousAPIsExtractor` and is safe for
the patterns that historically came from `JSFeaturesExtractor` — those literals
are spelled in real-world JS exactly as written.

`scan_source()` is the entry point used by extractors: it walks the source once
per pattern using the pre-compiled regexes and returns a flat
`{name: {"count": N, "lines": [unique_line_numbers_sorted]}}` dict. Both
`JSFeaturesExtractor` and `JSSuspiciousAPIsExtractor` consume the same dict so
the per-pattern × per-line loops they used to run independently collapse to a
single shared scan.
"""

import bisect
import re
from typing import Dict, Iterable, List, Mapping

_FLAGS = re.IGNORECASE

# Canonical compiled patterns, keyed by their human-readable name. The name is
# also the value emitted into `redb_js_suspicious_apis.api_name`.
PATTERNS = {
    # ---- code execution ----
    "eval": re.compile(r"\beval\s*\(", _FLAGS),
    "Function constructor": re.compile(r"\bnew\s+Function\s*\(", _FLAGS),
    "execScript": re.compile(r"\bexecScript\s*\(", _FLAGS),
    "document.write": re.compile(r"\bdocument\.write(?:ln)?\s*\(", _FLAGS),
    "innerHTML assignment": re.compile(r"\.innerHTML\s*=", _FLAGS),
    "outerHTML assignment": re.compile(r"\.outerHTML\s*=", _FLAGS),
    "insertAdjacentHTML": re.compile(r"\.insertAdjacentHTML\s*\(", _FLAGS),
    # ---- network ----
    "XMLHttpRequest": re.compile(r"\bnew\s+XMLHttpRequest\b", _FLAGS),
    "fetch": re.compile(r"\bfetch\s*\(", _FLAGS),
    "WebSocket": re.compile(r"\bnew\s+WebSocket\s*\(", _FLAGS),
    "navigator.sendBeacon": re.compile(r"\bnavigator\.sendBeacon\s*\(", _FLAGS),
    "ActiveXObject XMLHTTP": re.compile(
        r"ActiveXObject\s*\(\s*[\"\'](?:MSXML2\.XMLHTTP|Microsoft\.XMLHTTP)", _FLAGS
    ),
    "require network module": re.compile(
        r"require\s*\(\s*[\"\'](?:http|https|net|dgram)[\"\']", _FLAGS
    ),
    "axios": re.compile(r"\baxios\b", _FLAGS),
    # ---- filesystem ----
    "require fs": re.compile(r"require\s*\(\s*[\"\']fs[\"\']", _FLAGS),
    "require path": re.compile(r"require\s*\(\s*[\"\']path[\"\']", _FLAGS),
    "FileSystemObject": re.compile(r"Scripting\.FileSystemObject", _FLAGS),
    "ADODB.Stream": re.compile(r"ADODB\.Stream", _FLAGS),
    "Shell.Application": re.compile(r"Shell\.Application", _FLAGS),
    "WScript.CreateObject": re.compile(r"WScript\.CreateObject", _FLAGS),
    # ---- process ----
    "require child_process": re.compile(r"require\s*\(\s*[\"\']child_process[\"\']", _FLAGS),
    "child_process exec": re.compile(r"child_process\.(?:exec|spawn|execFile|fork)\s*\(", _FLAGS),
    "WScript.Shell": re.compile(r"WScript\.Shell", _FLAGS),
    "WScript.Shell.Run": re.compile(r"\.Run\s*\(", _FLAGS),
    "WScript.Shell.Exec": re.compile(r"\.Exec\s*\(", _FLAGS),
    "ShellExecute": re.compile(r"\bShellExecute\b", _FLAGS),
    "PowerShell reference": re.compile(r"[\"\']powershell[\"\']", _FLAGS),
    "cmd.exe reference": re.compile(r"[\"\']cmd\.exe[\"\']", _FLAGS),
    "require os": re.compile(r"require\s*\(\s*[\"\']os[\"\']", _FLAGS),
    # ---- registry ----
    "RegRead": re.compile(r"\.RegRead\s*\(", _FLAGS),
    "RegWrite": re.compile(r"\.RegWrite\s*\(", _FLAGS),
    "RegDelete": re.compile(r"\.RegDelete\s*\(", _FLAGS),
    "StdRegProv": re.compile(r"StdRegProv", _FLAGS),
    # ---- crypto / encoding ----
    "atob": re.compile(r"\batob\s*\(", _FLAGS),
    "btoa": re.compile(r"\bbtoa\s*\(", _FLAGS),
    "String.fromCharCode": re.compile(r"String\.fromCharCode\s*\(", _FLAGS),
    "unescape": re.compile(r"\bunescape\s*\(", _FLAGS),
    "decodeURIComponent": re.compile(r"\bdecodeURIComponent\s*\(", _FLAGS),
    "Buffer.from": re.compile(r"Buffer\.from\s*\(", _FLAGS),
    "crypto module": re.compile(r"crypto\.create(?:Cipher|Decipher|Hash|Hmac)", _FLAGS),
    # ---- DOM manipulation ----
    "document.forms": re.compile(r"document\.forms", _FLAGS),
    "document.cookie": re.compile(r"document\.cookie", _FLAGS),
    "querySelector sensitive input": re.compile(
        r"document\.querySelector\s*\([^)]*(?:password|credit|card|cvv|ssn)", _FLAGS
    ),
    "submit event listener": re.compile(r"addEventListener\s*\(\s*[\"\']submit", _FLAGS),
    "createElement script/iframe": re.compile(
        r"\.createElement\s*\(\s*[\"\'](?:script|iframe)", _FLAGS
    ),
    "dynamic script src": re.compile(r"\.src\s*=\s*[\"\'](?:https?://|//)", _FLAGS),
}

# Pattern name -> category (one of code_execution / network / filesystem /
# process / registry / crypto_encoding / dom_manipulation).
CATEGORIES = {
    "eval": "code_execution",
    "Function constructor": "code_execution",
    "execScript": "code_execution",
    "document.write": "code_execution",
    "innerHTML assignment": "code_execution",
    "outerHTML assignment": "code_execution",
    "insertAdjacentHTML": "code_execution",
    "XMLHttpRequest": "network",
    "fetch": "network",
    "WebSocket": "network",
    "navigator.sendBeacon": "network",
    "ActiveXObject XMLHTTP": "network",
    "require network module": "network",
    "axios": "network",
    "require fs": "filesystem",
    "require path": "filesystem",
    "FileSystemObject": "filesystem",
    "ADODB.Stream": "filesystem",
    "Shell.Application": "filesystem",
    "WScript.CreateObject": "filesystem",
    "require child_process": "process",
    "child_process exec": "process",
    "WScript.Shell": "process",
    "WScript.Shell.Run": "process",
    "WScript.Shell.Exec": "process",
    "ShellExecute": "process",
    "PowerShell reference": "process",
    "cmd.exe reference": "process",
    "require os": "process",
    "RegRead": "registry",
    "RegWrite": "registry",
    "RegDelete": "registry",
    "StdRegProv": "registry",
    "atob": "crypto_encoding",
    "btoa": "crypto_encoding",
    "String.fromCharCode": "crypto_encoding",
    "unescape": "crypto_encoding",
    "decodeURIComponent": "crypto_encoding",
    "Buffer.from": "crypto_encoding",
    "crypto module": "crypto_encoding",
    "document.forms": "dom_manipulation",
    "document.cookie": "dom_manipulation",
    "querySelector sensitive input": "dom_manipulation",
    "submit event listener": "dom_manipulation",
    "createElement script/iframe": "dom_manipulation",
    "dynamic script src": "dom_manipulation",
}

# Patterns consumed only by JSFeaturesExtractor (no category, never surfaced as
# a suspicious-API row). Kept here so every JS regex is compiled in one place.
FEATURE_PATTERNS = {
    "hex_escape": re.compile(r"\\x[0-9a-fA-F]{2}"),
    "unicode_escape": re.compile(r"\\u[0-9a-fA-F]{4}"),
    "base64_string": re.compile(r"[A-Za-z0-9+/]{40,}={0,2}"),
    # decodeURI matches BOTH decodeURI and decodeURIComponent. The latter is also
    # a suspicious-API pattern in PATTERNS; this broader form is what the
    # `decodeuri_count` feature column has historically counted.
    "decodeURI": re.compile(r"\b(?:decodeURI|decodeURIComponent)\s*\(", _FLAGS),
    "settimeout_setinterval": re.compile(r"\b(?:setTimeout|setInterval)\s*\(", _FLAGS),
    "function_decl": re.compile(r"\bfunction\s+\w+\s*\(|\bfunction\s*\("),
    "var_decl": re.compile(r"\b(?:var|let|const)\s+"),
    "string_concat": re.compile(r"[\"\'][\s]*\+[\s]*[\"\']"),
    "comment": re.compile(r"//.*?$|/\*[\s\S]*?\*/", re.MULTILINE),
    "long_string": re.compile(r"[\"\']([^\"\']{256,})[\"\']"),
    "array_function_call": re.compile(r"\[(?:0x[0-9a-f]+|[\d]+)\]\s*\(", _FLAGS),
}

# Patterns consumed only by JSStringsExtractor for encoded-string discovery.
# Scoped to *hidden* strings only — patterns whose decoded form is not visible
# to a substring search over the raw text. Plain long literals are not
# extracted here because they're already preserved in code_text_content and
# scraped by the IOC pipeline over text_raw / text_normalized.
#
# Distinct from FEATURE_PATTERNS even where the names rhyme:
#   FEATURE_PATTERNS["hex_escape"] / ["unicode_escape"]   -> single escape
#   STRING_PATTERNS["hex_escape_seq"] / ["unicode_escape_seq"] -> 4+ / 3+ in a row
#   FEATURE_PATTERNS["base64_string"]                     -> bare base64 token
#   STRING_PATTERNS["base64_quoted"]                      -> base64 inside JS quotes
# These do not share match objects with the suspicious-API or feature scans, so
# they are not folded into JSContext.scan; the strings extractor walks them
# itself (one finditer per pattern, with shared line-offset bisect in #4b).
STRING_PATTERNS = {
    "hex_escape_seq": re.compile(r"(?:\\x[0-9a-fA-F]{2}){4,}"),
    "unicode_escape_seq": re.compile(r"(?:\\u[0-9a-fA-F]{4}){3,}"),
    "charcode_call": re.compile(r"String\.fromCharCode\s*\(\s*([\d,\s]+)\s*\)"),
    "base64_quoted": re.compile(r"[\"\']([A-Za-z0-9+/]{40,}={0,2})[\"\']"),
    "concat_chain": re.compile(r"(?:[\"\'][^\"\']+[\"\']\s*\+\s*){3,}[\"\'][^\"\']+[\"\']"),
}


def line_offsets(source: str) -> List[int]:
    """Sorted list of byte offsets for every newline in `source`, plus a final
    sentinel of len(source). Used to translate match offsets into 1-indexed
    line numbers via bisect.
    """
    offsets = [-1]  # so that bisect_right of offset 0 returns line 1
    push = offsets.append
    idx = source.find("\n")
    while idx != -1:
        push(idx)
        idx = source.find("\n", idx + 1)
    return offsets


def _scan_one(
    pattern: "re.Pattern[str]", source: str, offsets: List[int]
) -> Dict[str, object]:
    """Run a single compiled pattern over `source` and return count + unique lines."""
    count = 0
    seen_lines: "set[int]" = set()
    for m in pattern.finditer(source):
        count += 1
        seen_lines.add(bisect.bisect_right(offsets, m.start()))
    if not count:
        return None  # type: ignore[return-value]
    return {"count": count, "lines": sorted(seen_lines)}


def scan_source(
    source: str,
    patterns: Iterable[Mapping[str, "re.Pattern[str]"]] = (PATTERNS, FEATURE_PATTERNS),
) -> Dict[str, Dict[str, object]]:
    """Scan `source` against every compiled pattern in `patterns`.

    Returns a dict keyed by pattern name. Each entry has:
        "count": total number of matches in the source
        "lines": sorted list of unique 1-indexed line numbers where the pattern
                 matched (deduplicated — multiple matches on the same line
                 collapse to one entry, preserving the historical
                 line-set semantics of JSSuspiciousAPIsExtractor)
    Patterns with zero matches are absent from the dict; callers should default
    to {"count": 0, "lines": []}.
    """
    if not source:
        return {}
    offsets = line_offsets(source)
    results: Dict[str, Dict[str, object]] = {}
    for table in patterns:
        for name, pat in table.items():
            entry = _scan_one(pat, source, offsets)
            if entry is not None:
                results[name] = entry
    return results