{"id":31770024,"url":"https://github.com/jfrog/text4shell-tools","last_synced_at":"2025-10-10T02:56:29.887Z","repository":{"id":61639833,"uuid":"553464155","full_name":"jfrog/text4shell-tools","owner":"jfrog","description":null,"archived":false,"fork":false,"pushed_at":"2022-10-24T08:11:55.000Z","size":789,"stargazers_count":104,"open_issues_count":3,"forks_count":20,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-10-23T00:41:51.234Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jfrog.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-10-18T08:57:19.000Z","updated_at":"2024-08-12T20:27:52.000Z","dependencies_parsed_at":"2023-01-20T09:45:43.971Z","dependency_job_id":null,"html_url":"https://github.com/jfrog/text4shell-tools","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/jfrog/text4shell-tools","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfrog%2Ftext4shell-tools","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfrog%2Ftext4shell-tools/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfrog%2Ftext4shell-tools/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfrog%2Ftext4shell-tools/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jfrog","download_url":"https://codeload.github.com/jfrog/text4shell-tools/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jfrog%2Ftext4shell-tools/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":279002512,"owners_count":26083403,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-10T02:00:06.843Z","response_time":62,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-10-10T02:56:23.665Z","updated_at":"2025-10-10T02:56:29.881Z","avatar_url":"https://github.com/jfrog.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# commons-text-tools\n\n### Quick links\n\nClick to find:\n\n- [Find `commons-text` .jar files and their versions](#scan_commons_text_versionspy)\n- [Calls to `commons-text` vulnerable functions](#scan_commons_text_calls_jarpy) \n- [Hot patch on `commons-text` .jar files to disable the vulnerable behaviors](#text_4_shell_patch)\n\n- [Scan and patch example](#4-can-i-automate-scanning-and-patching-of-vulnerable-commons-text-jar)\n\n\n### Overview\n\nCVE-2022-42889 may pose a serious threat to a wide range of Java-based applications. The important questions a developer may ask in this context are:\n\n### 1. Does my code include `commons-text`? Which versions?\n\nDoes the released code include `commons-text`? Which version of the library is included there? Answering these questions may not be immediate due to two factors:\n\n1) Transitive dependencies: while `commons-text` may not be in the direct dependency list of the project, it may be used indirectly by some other dependency.\n\n2) The code of this library may not appear directly as a separate file, but rather be bundled in some other code jar file.\n\nJFrog is releasing a tool to help resolve this problem: [`scan_commons_text_versions`](#scan_commons_text_versionspy). The tool looks for the **class code** of `StringLookupFactory`  **(regardless of containing `.jar` file names and content of `pom.xml` files)**, and attempts to fingerprint the versions of the objects to report whether the included version of `commons-text` is vulnerable.\n\n### 2. Does my code use vulnerable `commons-text` functions? \n\nThe question is relevant for the cases where the developer would like to verify if the calls to `commons-text` in the codebase may pass potentially attacker-controlled data. While the safest way to fix the vulnerability, as discussed in the advisories, is to apply the appropriate patches, controlling for and verifying the potential impact under assumption of unpatched `commons-text` may be valuable in many situations. \n\n[`scan_commons_text_calls_jar.py`](#scan_commons_text_calls_jarpy), which locates the calls to the vulnerable functions in *compiled .jar*s, and reports the findings as class name and method names in which each call appears.\n\n\n### 3. I have vulnerable `commons-text` jar files in my system, how can I quickly disable the dangerous behavior?\n\n* Updating remains the best solution - this solution is intented for fast hot patching\n\n* In the context of CVE-2022-42889 vulnerability, the class `org/apache/commons/text/lookup/ScriptStringLookup` in `commons-text` enables execution of scripts which may be embedded in a string received from an attacker-controlled source through `${script}`. Therefore, invocations of `ScriptStringLookup.lookup` function are indicative of the functionality being activated.\n\n* We provide a tool, [`Text4ShellPatch`](#text_4_shell_patch), allowing to patch this specific call so that the script execution functionality cannot be utilized. After applying the patch, the library will always execute a script returning a warning message (instead of the potentially attacker-controlled code)\n* Similarly, DNS and URL lookup can load untrusted content if controlled by an attacker through `${dns}` and `${url}`, thus, their respective lookup `DnsStringLookup` and `UrlStringLookup` respectively can be disabled through patch to return a warning message,\n* The patch can be applied to a specific jar file, for the `script` lookup only or `script`, `dns` and `url` for a better protection in case it is not meant to be used in the application, \n* A backup is generated in the same location as the original jar before being replaced with the patch one. The backup filename follows the following pattern: `\u003coriginal_jar_name\u003e_YYYY.MM.DD_HH.mm.ss.orig.jar` where `YYYY`, `MM`, `DD` are respectively the year, the month and the day, and `HH`, `mm`, `ss` are respectively the hour, the minutes and the second. \n* It is also possible to locate vulnerable versions of `commons-text` and patch them automatically as the next question answers to it.\n\n\n### 4. Can I automate scanning and patching of vulnerable `commons-text` jar?\n\nTwo of our tools together offers the ability to scan and patch the vulnerable `commons-text` jar files. \n\nAn example bash script is present in this Github repository under the name of `scan_and_patch.sh`. Basically, it is using the `scan_commons_text_versions.py` script to find under a specific `root-folder` the vulnerable `commons-text` jar files with a vulnerable version and run the `Text4ShellPatch` tool against them as follows.  \n\n![Example of automation](images/example_scan_and_patch.PNG)\n\n------\n\n### `scan_commons_text_versions.py`\n##### Usage\n\n```\npython scan_commons_text_versions.py root-folder [-quiet] [-exclude folder1 folder2 ..]\n```\n\nThe tool will scan `root_folder` recursively for `.jar` and `.war` files; in each located file the tool looks for a `StringLookupFactory.class` (recursively in each `.jar` file). If at least one of the classes is found, the tool attempts to fingerprint its version (including some variations found in patches and backport patches) in order to report whether the code is vulnerable.\n\nWith `-quiet` flag, only version conclusions are printed out, and other messages (files not found/ archives failed to open/ password protected archives) are muted.\n\nFolders appearing after `-exclude` (optional) are skipped.\n\n------\n\n### `scan_commons_text_calls_jar.py`\n\nThe tool requires python 3 and the following 3rd party libraries: `jawa`, `tqdm`, `easyargs`, `colorama`\n\n##### Dependencies installation\n\n```\npip install -r requirements.txt\n```\n\n##### Usage\n\nThe default use case:\n\n```\npython scan_commons_text_calls_jar.py root-folder\n```\n\nwill recursively scan all `.jar` files in `root-folder`, for each printing out locations (class name and method name) of calls to `lookup`/`replace`/`replaceIn` methods of `StringSubstitutor`/`StringLookup`. \n\nThe tool may be configured for additional use cases using the following command line flags.\n\n| Flag                  | Default value        | Use                                                          |\n| --------------------- | -------------------- | ------------------------------------------------------------ |\n| `--class_regex`       | (.*StringSubstitutor\u0026#124;.*StringLookup)       | Regular expression for required class name                   |\n| `--method_regex`      | (lookup\u0026#124;replace\u0026#124;replaceIn)                 | Regular expression for required method name                  |\n| `--quickmatch_string` | (StringLookup\u0026#124;StringSubstitutor)                | Pre-condition for file analysis: .jar files not containing the specified regex will be ignored |\n| `--class_existence`   | Not set              | When not set, look for calls to class::method as  specified by regexes. When set, `--method_regex` is ignored, and the tool will look for *existence* of classes specified by `--class_regex` in the jar. |\n| `--no_quickmatch`     | Not set              | When set, the value of `--quickmatch_string` is ignored and all jar files are analyzed |\n| `--caller_block`      | .*org/apache/commons/text | If caller class matches this regex, it will *not* be displayed |\n\n------\n\n### `text_4_shell_patch`\n##### Usage\n\n```\njava -jar Text4ShellPatch.jar TARGET_JAR [PATCHING_MODE]\n  Where TARGET_JAR is the application to patch and PATCHING_MODE is\n    0 (default): Patch Script lookup\n    1:           Patch Script + DNS + URL lookups\n  [Note: The original Jar will be kept in the same folder with the .orig.jar extension]  \n```\n\nThe tool will look for the `org/apache/commons/text/lookup/ScriptStringLookup` class in the `commons-text` jar given and replaces the `lookup()` function's content by a warning message and return out of the function. Thus, the `eval` will not exist in the new `ScriptStringLookup` class.\n\nIt can also patch the `DnsStringLookup` and `URLStringLookup` classes and disable the `lookup()` function when setting the `PATCHING_MODE` option to 1. \n\nA backup file is generated through the process in the same path with the `.orig.jar` extension. \n\n##### Generation from Code-Source\n\nText4ShellPatch can be edited and compiled with Maven with the simple command:\n` mvn clean assembly:single `. It will create a `Text4ShellPatch.jar` file in the `target/` folder.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjfrog%2Ftext4shell-tools","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjfrog%2Ftext4shell-tools","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjfrog%2Ftext4shell-tools/lists"}