Skip to main content

wowlab_tidy/languages/rust/rules/correctness/
bidirectional_unicode.rs

1use crate::{Example, FileCtx, Violation, violation};
2
3#[rustfmt::skip]
4const EXAMPLES: &[Example] = &[
5    Example {
6        label: "bidi LRE character",
7        code: "let x = \"\u{202A}test\";",
8        pass: false,
9    },
10    Example {
11        label: "bidi RLO character",
12        code: "let x = \"\u{202E}test\";",
13        pass: false,
14    },
15    Example {
16        label: "normal ASCII",
17        code: "let x = \"hello world\";",
18        pass: true,
19    },
20    Example {
21        label: "bidi LRM character",
22        code: "let x = \"\u{200E}test\";",
23        pass: false,
24    },
25];
26
27crate::line_rule!(
28    bidirectional_unicode,
29    "Ban Unicode bidi control characters that enable trojan-source attacks.",
30    "Bidi control characters can reorder displayed code to hide malicious logic (CVE-2021-42574).",
31    High,
32);
33
34const BIDI_CHARS: &[char] = &[
35    '\u{202A}', // LRE
36    '\u{202B}', // RLE
37    '\u{202C}', // PDF
38    '\u{202D}', // LRO
39    '\u{202E}', // RLO
40    '\u{2066}', // LRI
41    '\u{2067}', // RLI
42    '\u{2068}', // FSI
43    '\u{2069}', // PDI
44    '\u{200E}', // LRM
45    '\u{200F}', // RLM
46];
47
48fn check_bidirectional_unicode(ctx: &FileCtx<'_>) -> Vec<Violation> {
49    let mut out = Vec::new();
50
51    for (i, line) in ctx.lines.iter().enumerate() {
52        let lineno = i + 1;
53
54        for ch in BIDI_CHARS {
55            if line.contains(*ch) {
56                out.push(violation(
57                    ctx.rel,
58                    lineno,
59                    format!(
60                        "bidirectional Unicode control character U+{:04X} (trojan-source risk)",
61                        *ch as u32
62                    ),
63                ));
64                break;
65            }
66        }
67    }
68
69    out
70}
71
72crate::tidy_test!(check_bidirectional_unicode, {
73    crate::example_tests!(EXAMPLES, check_bidirectional_unicode);
74});