BLOG

729★ 'AI Text Humanizer' Confirmed as Poisoned: C2 Address Hidden in main.py

Kael Zhang
AI安全供应链安全开源软件
广告 · Advertisement

First, a declaration of safety boundaries: the repository korcarc/text-humanizer dissected in this article is a malicious sample. Any reader must not clone, install, or run it. Readers who have already installed it should uninstall it immediately and check for abnormal network connections on Windows machines. All conclusions in this article come from statically reading source code and mathematically decoding encrypted payloads; no code from the repository was executed during the process.

The GitHub repository korcarc/text-humanizer, created on September 16, 2026, garnered 729 stars and 83 forks by September 20. It is written in Python under the MIT license. The README’s selling point is blunt: a four-stage translation and rewriting pipeline—DeepSeek rewriting, Google Translate English to Turkish, optional DeepL Turkish to Japanese, DeepSeek back-translation to the original text—claiming to “bypass most AI detectors like Turnitin/GPTZero” and recommending setting temperature to 1.3. In other words, it targets the crowd with an essential need for “removing AI flavor.” This article breaks it down into six parts: what it is, the bait logic, how the mechanism works, three points in the source code worth watching, boundaries and protection, and whether it’s worth it and the correct approach.

1. What is this

Nominally, text-humanizer is a text rewriting tool: you give it AI-generated text, it runs a four-stage translation chain to make the text “not look machine-written,” while claiming to pass mainstream AI detectors. The README looks like a legitimate project, with usage examples, parameter descriptions, and a list of supported languages—except the language list itself doesn’t match: it claims 8 languages, but actually lists en/ja/zh/ko/de/fr/es, totaling 7.

Static reading of the repo reveals three discrepancies with the README. First, the core functionality promised in the README simply cannot run: src/standard/llm_rewriter.py contains from .llm_client import chat_completions, but the file llm_client.py does not exist, so the entire DeepSeek pipeline breaks at the import stage. Second, src/conversion/translation_chain.py, nominally a translation module, has 1403 lines, yet the content is a complete Bitcoin key library—ECDSA, secp256k1, Taproot, WIF signatures—having nothing to do with translation. No file in the repo imports it, and requirements.txt doesn’t list its dependencies; it is a piece of carefully placed dead code. Third, the only live code in main.py is line 12, humanizer.run_sync()—from import to network execution is just one step, and humanizer.py is misnamed: it is a payload with two layers of encryption. Three mismatches: promise doesn’t match files, filename doesn’t match content, project name doesn’t match behavior.

2. Bait Logic: Why this one

To understand this sample, one must first understand its target audience. AI detector bypassing sits in a gray area of academic integrity—on one side are students wanting to submit assignments, on the other are marketing accounts wanting to mass-post content. Both have a strong need to “get text past detection” but cannot publicize it. This demand naturally pushes people toward the gray corners of search engines and GitHub: legitimate channels won’t sell such tools, so unverified repositories become the only shelf.

The poisoner chose the product accurately. This audience has three characteristics, each lowering the risk of sample exposure: they don’t read source code—install-and-run is the expectation; they dare not speak up—if hit, they mostly accept their bad luck; they lack troubleshooting experience—they won’t notice multiple strange processes on their machines. Even if only one-tenth of the 729 stars are real users who ran main.py, the delivery efficiency is already considerable.

Incidentally, the account level also doesn’t match. The author, korcarc, registered in April 2020. For over four years, this has been their only public repository, with only 6 followers. An account dormant for four years posting 729 stars in three days—this combination doesn’t prove anything on its own, but stacked with the three discrepancies in the code, the direction is clear: the repository’s popularity composition doesn’t match the account history. Readers taking the star count at face value as an endorsement will suffer.

3. Mechanism: The chain from import to C2

3.1 Step 1: Execution upon import

The effective code in main.py is just one line. Line 12, humanizer.run_sync(), is at the module’s top level, meaning anyone running python main.py or importing this package will trigger this line immediately—no switch, no confirmation, no dry-run. For normal usage scenarios, this is counter-intuitive design—legitimate libraries wait until you call them. For poisoners, this is the shortest path.

3.2 Step 2: The double-layer encrypted humanizer.py

src/services/humanizer.py is the most technically interesting file in this repo: only 42 lines, but 28.6KB. Averaging nearly 700 bytes per line, this is compressed ciphertext. Peeling it back reveals a trio, explained layer by layer.

First layer: String XOR obfuscation. All readable identifiers, constants, and URLs are XORed with a fixed key. A static grep scan finds no keywords—no http, no socket, nothing resembling malware.

Second layer: HMAC-SHA256 counter stream. This is a standard stream encryption construction: feed the key and an incrementing counter into HMAC-SHA256 to generate a keystream equal in length to the ciphertext, then XOR to restore the plaintext. It is an order of magnitude more advanced than the first layer’s fixed XOR—the same plaintext encrypts differently each time, so direct byte comparison finds no pattern.

Third layer: zlib compression. After stream decryption, it passes through a standard zlib decompression to get the final Python source code, which is then injected into the current module’s globals via builtins.exec to define run_sync. The file also includes an anti-tampering check: a series of constants participate in decryption parameters; if the ciphertext is altered by a single byte, the decryption result is unrecognizable, and run_sync is never born. In other words, this payload is immune to any form of patching attempt—you want to patch it and run it to see what it does? Sorry, change one byte and it won’t decrypt.

This combination wasn’t written casually. XOR blocks keyword scanning, HMAC stream blocks byte-level analysis, zlib blocks structural recognition, and anti-tampering blocks security researchers’ patching experiments. For the vast majority of users who “install a package to try,” the first three layers are enough.

3.3 Step 3: What the decrypted payload does

Static decoding (pure mathematical operations, no code execution) reveals the payload’s behavior as follows. It initiates a plaintext HTTP request to C2 address 172.239.96.53:8765, with the authentication header being a hardcoded Bearer token 094750aeef51f8e9d0c126b879c9df07. It downloads the second-stage module from /api/v1/client/manual_mapper.py and writes it to the pseudo-path <ram:>—executing only in memory, without touching the disk. Subsequently, it calls manual_mapper.map_from_server(...) with PAYLOAD_KEY 7c2101e76c97188da4c56d9c2f31712c to pull the final payload.

Three design details are worth pointing out individually. First, full plaintext HTTP: the token and key lie directly in the traffic, indicating the operator either isn’t worried about reverse engineering (the code is encrypted anyway) or is cutting corners—this doesn’t look like the work of an expert, more like “good enough” mass production. Second, effective only on Windows: non-win32 environments directly throw “win32 only”; the payload knows what system it is on. Third, QUIET=True defaults to silent: all exceptions are swallowed, outputting no information to the user.

These three things together form the evasion trio. Memory execution means antivirus software scanning the disk finds nothing—there is never a malicious file on the filesystem, only an encrypted Python source. Windows-only restricts the true form to the largest, least security-conscious, and least likely desktop system to be used daily by security researchers. Silent error handling as a fallback: even if it fails, it leaves no trace. Mac and Linux users running it see only a quiet error or no output at all; most won’t be suspicious, let alone investigate. The truly hit Windows users are using unverified “detector bypass tools,” an identity that naturally discourages them from seeking help from legitimate security software.

The content of the final payload is unknown—it is decided at runtime by the C2 server, depending on the actually downloaded module. The only reasonable inference is this: a delivery channel tailored for the detector bypass crowd, likely loaded with info-stealing payloads, but this is speculation and doesn’t count as the main text.

4. Three points in the source code worth watching

4.1 humanizer.py: An engineering sample of the trio

42 lines, 28.6KB, triple encryption plus anti-tampering plus exec injection—this file itself is a confusion textbook worth collecting. Its educational value lies not in malice, but in demonstrating the standard playbook static analysis must deal with: keyword scanning blocked by XOR, byte comparison blocked by HMAC stream, structural recognition blocked by zlib, patching experiments blocked by anti-tampering. Each layer alone is public technology; combined, it is a shell quite unfriendly to automated detection. Next time you see a Python file that is “only a few dozen lines but several MB” or “grep finds no strings,” this should be your first reaction.

4.2 translation_chain.py: A 1403-line Bitcoin key library

The nominally translation chain file is actually a vendored Bitcoin key library: ECDSA, secp256k1, Taproot, WIF signatures, all present. It has nothing to do with translation. No one in the repo imports it, and requirements.txt doesn’t list dependencies for it—ecdsa, base58check, sympy, bitcoinutils are all missing. Its role here probably has two explanations: one is to pad the repo volume and line count to make the project look substantial; two is that if asked, one can claim “blockchain-related plans.” Either way, it is a marker testing whether the reader actually reads source code: people who notice this file is fishy are unlikely to continue running main.py.

4.3 llm_rewriter.py: A deliberately broken chain

The entry point for the DeepSeek pipeline promised in the README is here: from .llm_client import chat_completions—and llm_client.py does not exist. This isn’t negligence, because nowhere in the entire repo is chat_completions defined. In other words, the “four-stage translation rewriting” function that attracted users most in the README was never implemented; any user following the README instructions gets an ImportError at the import stage. The poisoner doesn’t care: they just need to lead people to the python main.py step; the functionality afterward is just scenery. The fact that the functionality doesn’t run proves the scenery doesn’t need to be real—as long as the README looks like it.

5. Boundaries and Protection

Three points of doubt, written only as doubts, not conclusions. The final payload content is unknown, distributed by C2 at runtime, and could be anything. The operator’s identity is unknown, account info is near blank, and attribution is impossible. The star composition is doubtful—729 stars in three days clearly mismatches the account history; the proportion of real users is impossible to verify.

For protection, I offer readers three actionable things. First, before installing any package, spend two minutes opening its main.py or entry file: is there a call that executes immediately upon import at the top level? Do the filename and content match (grep a file named translation_chain to see if it contains “translate”)? Does the functionality promised in the README match the number of files? These three questions don’t require coding knowledge. Second, pin dependency versions and audit: this repo’s requirements.txt abruptly pins tornado==6.4.2; the dependency list itself should trigger a “why this one” suspicion—normal projects have no reason to pin an exact version of a framework they don’t use. Third, do not pip install unverified “detector bypass” tools: a tool that actively teaches you to break rules offers you no means to constrain it to follow rules. There is no after-sales service in the gray zone; this holds true for both buyers and victims.

For the GitHub platform level, the recognition characteristics of such samples are already patterned: old accounts dormant for years, suddenly created, README written more than code, star growth speed mismatching account assets, code body is ciphertext or dead code. Looking at any one alone might be a coincidence; three or more appearing simultaneously, just close the page.

6. Worth it and the correct approach

There is little point discussing whether this tool is worth it; it is a sample worth collecting for an identification handbook. It demonstrates the standard moves of supply chain poisoning, from bait selection, obfuscation engineering to platform-side camouflage, every step has textbook traces. For security researchers, the trio encryption plus anti-tampering is a confusion paradigm worth writing in notes; for ordinary readers, it validates a simple experience: star count is not a security endorsement, README is not proof of functionality, and between “can run” and “can run safely” lies an entire session of source code reading.

The correct approach to “removing AI flavor” is not in gray tools. This account’s daily practice has always been whitelist rewriting plus manual rewriting: first think clearly what this text wants to say, then rewrite it in your own words, and finally treat AI-generated content as a draft, not a finished product. This path doesn’t bypass any detectors because the goal is to make the text truly human. Detectors like GPTZero and Turnitin are also in a gray zone—they misidentify human writing and fail to stop those determined to bypass. Betting on “tricking them” yields, regardless of success or failure, a text that doesn’t belong to you and a potentially poisoned process.

Conclusion

text-humanizer used a well-written README to answer “how to bypass AI detectors,” and used source code to answer “how to bypass your defenses.” Line 12 of main.py executes upon import; humanizer.py wraps an anti-tampering payload in triple encryption of XOR plus HMAC-SHA256 stream plus zlib; after decryption, it initiates plaintext HTTP to 172.239.96.53:8765, downloads a second-stage module with a hardcoded Bearer token, executes only in memory, is effective only on Windows, and silently swallows all exceptions by default; the 1403-line Bitcoin key library and the import of non-existent llm_rewriter.py are responsible for making the repo look like a project. 729 stars in three days versus an account with one repo in four years and six followers don’t match; functional promises don’t match code that can’t run; translation filenames don’t match Bitcoin key libraries. Three mismatches constitute its entire self-introduction. Finally, reiterate the safety boundary: do not clone, do not install, do not run this repository.

References

  • korcarc/text-humanizer README (four-stage pipeline, bypass detection claims, language list, temperature recommendation)
  • Source code static reading (no execution): main.py (line 12 humanizer.run_sync()), src/services/humanizer.py (42 lines 28.6KB, XOR obfuscation, HMAC-SHA256 counter stream, zlib, exec injection, anti-tampering check), src/conversion/translation_chain.py (1403 lines Bitcoin key library, no imports), src/standard/llm_rewriter.py (imports non-existent llm_client.py), requirements.txt (tornado==6.4.2)
  • Payload static decoding (pure mathematical operations, no execution): C2 172.239.96.53:8765, Bearer 094750aeef51f8e9d0c126b879c9df07, manual_mapper.py memory execution, win32 only, QUIET=True, PAYLOAD_KEY 7c2101e76c97188da4c56d9c2f31712c
  • Repository data: 729★, 83 forks, created on 2026-09-16, author account registered 2020-04, public repos 1, followers 6 (as of 2026-09-20).
广告 · Advertisement

Frequently Asked Questions

Is text-humanizer really malware?

Three chains of evidence from static dissection point to the same conclusion: in the four-stage translation and rewriting pipeline promised by the README, llm_rewriter.py imports a non-existent llm_client.py, so the functionality was never implemented. The so-called translation file translation_chain.py is actually a 1403-line Bitcoin key library; it is not referenced by anyone, lacks dependencies, and is dead code padding the repository. The only live code in main.py is `humanizer.run_sync()` at line 12, which executes upon import, while humanizer.py is a triple-encrypted payload of XOR obfuscation + HMAC-SHA256 counter stream + zlib. After decryption, it connects to C2 address 172.239.96.53:8765, downloads manual_mapper.py using a hardcoded Bearer token, executes only in memory, is effective only on win32 systems, and silently swallows all exceptions by default.

Why does this type of poisoning specifically target "AI detector bypass" tools?

The target audience has three characteristics that reduce exposure risk: they don't read source code—install-and-run is the expectation; they dare not speak up—if hit, they mostly accept their bad luck; they lack troubleshooting experience—they won't notice multiple strange processes on their machine. Unverified repositories are the only shelf for this gray demand: legitimate channels won't sell them, so corners of search engines and GitHub become placement spots. Even if only one-tenth of the 729 stars are real users who ran main.py, the delivery efficiency is already considerable.

How can ordinary developers prevent pip supply chain poisoning?

Three actionable things: before installing any package, spend two minutes opening the entry file and ask three questions that don't require coding knowledge—is there a call that executes immediately upon import at the top level? Do the filename and content match (e.g., does a file named translation_chain actually contain "translate" inside)? Does the functionality promised in the README match the number of files? Dependency lists should pin versions and be audited; a project pinning an exact version of a framework it doesn't use for no reason should trigger suspicion. Do not install unverified "detector bypass" tools—a tool that actively teaches you to break rules offers you no means to constrain it to follow rules.