Overclocking Time's A tech blog by a 20-something Japanese female startup contractor and "struggling" engineer!
  • Home
  • Blog
JA EN
☰ Contents
    March 13, 2026
    #Generative AI#Tech

    Explaining Code Tamper-Proofing: A Case Study on Disabling the "Face Fusion" NSFW Filter

    Explaining Code Tamper-Proofing: A Case Study on Disabling the "Face Fusion" NSFW Filter

    This article was previously published as paid content on another site. Please refer to the latest documentation for any outdated information. If you are specifically interested in the FaceFusion filter removal, feel free to skip to the latter sections.

    Navigating "Tamper-Proofing" in Git Repository Distribution

    When distributing open-source software or applications, every engineer has likely faced a situation where they think, "I really don't want users to modify this data arbitrarily."

    Typical scenarios include:

    • Preventing users from removing a built-in Adult Content Filter (NSFW).
    • Preventing users from modifying config files to force behaviors the app wasn't designed for.

    To prevent these situations, the method of hashing files to verify integrity is commonly used.

    Representative Techniques for Tampering Prevention

    1. Integrity Checks via Hashing

    This is the simplest and most accessible method.

    import hashlib
    import sys
    import pathlib
    
    EXPECTED_HASH = "c157a79031e1c40f85931829bc5fc552"  # Example: MD5
    TARGET_FILE = pathlib.Path("filter_config.json")
    
    def file_hash(path: pathlib.Path) -> str:
        h = hashlib.md5()
        with path.open("rb") as f:
            for chunk in iter(lambda: f.read(8192), b""):
                h.update(chunk)
        return h.hexdigest()
    
    if not TARGET_FILE.exists():
        print("Required file is missing. Exiting.")
        sys.exit(1)
    
    if file_hash(TARGET_FILE) != EXPECTED_HASH:
        print("File has been tampered with. Exiting.")
        sys.exit(1)
    
    print("Started successfully.")
    

    This mechanism checks the "hash of critical files" at startup and terminates the process if there is a mismatch.

    • Pros: Easy to implement; provides a solid deterrent against general users who just follow online tutorials.
    • Cons: Anyone who can read the source code can simply delete the validation logic itself.

    2. Guarantees via Digital Signatures

    • Attach a signature to files during distribution.
    • Embed a public key within the app and verify the signature at startup.

    Since signature verification fails if a file is modified, this is more reliable than a simple hash check. However, integrating the signing process into your workflow can be a bit of a hassle.

    3. Server-Side Validation

    • Send hashes of critical files to a server at startup.
    • The server performs the comparison and grants permission to run only if they match.

    Even if the local validation logic is rewritten, the server holds the final "veto" power, making this very difficult to bypass. However, this method isn't viable for tools intended to work entirely offline.

    Thinking Within the Context of Git Distribution

    If you are distributing source code directly via GitHub or similar platforms, the conclusion is: It is impossible to make it "absolutely untamperable." Anyone capable of reading the code can just strip out the validation logic.

    You might wonder, "Then is there any point?" Absolutely. When an average user follows the standard "clone → build → execute" flow, these checks remain intact. It functions perfectly well as an effective barrier against unintentional or amateur modifications.

    Practical Choices

    Objective Best Option
    "Detecting tampering is enough" Hash Check
    "Only official releases should be trusted" GPG Signing
    "Absolutely never allow modified versions to run" Server-Side Validation + Signing

    Combining these methods is usually the most realistic approach.

    Tamper-Proofing in FaceFusion

    FaceFusion, a face-swapping tool for videos and images, includes a mechanism to detect and block sexual content. Under normal use, if content is flagged as NSFW (Not Safe For Work), the process stops as a protective measure.

    GitHub - facefusion/facefusion: Industry leading face manipulation platform
    Industry leading face manipulation platform. Contribute to facefusion/facefusion development by creating an account on G…
    GitHub

    Bypass methods for this are scattered across the web, but from my research, the latest versions have improved their defenses, rendering old information mostly useless. In this regard, the developers' countermeasures have been quite successful.

    Looking at FaceFusion's NSFW Measures

    The common trick of "changing the return value of facefusion/content_analyser.py to False to skip the filter" has already been countered. If you simply rewrite it, an internal error occurs, and the startup fails without telling the user why.

    def detect_nsfw(vision_frame : VisionFrame) -> bool:
        # NSFW filter disabled - always return False
        return False
        
        # Original code commented out:
        # is_nsfw_1 = detect_with_nsfw_1(vision_frame)
        # is_nsfw_2 = detect_with_nsfw_2(vision_frame)
        # is_nsfw_3 = detect_with_nsfw_3(vision_frame)
        # return is_nsfw_1 and is_nsfw_2 or is_nsfw_1 and is_nsfw_3 or is_nsfw_2 and is_nsfw_3
    

    How to Actually Bypass It (Technical Breakdown)

    Perhaps because bypass methods became too widespread, further defensive measures were implemented (Information as of Oct 17, 2025).

    Note: This is strictly a case study on code tampering countermeasures. It is not an endorsement for disabling filters.

    Take a look at the following code. The logic relies on the return value of the core NSFW filter.

    def detect_nsfw(vision_frame : VisionFrame) -> bool:
        is_nsfw_1 = detect_with_nsfw_1(vision_frame)
        is_nsfw_2 = detect_with_nsfw_2(vision_frame)
        is_nsfw_3 = detect_with_nsfw_3(vision_frame)
    
        return is_nsfw_1 and is_nsfw_2 or is_nsfw_1 and is_nsfw_3 or is_nsfw_2 and is_nsfw_3
    

    If this returns True (NSFW detected), the subsequent processing is forced to terminate.

    Trying to Return "Non-NSFW" for Everything

    If True stops the process, you'd think forcing a False (Safe) return would bypass the censorship. However, doing so causes the process to exit silently without any errors.

    This is because the aforementioned integrity check via hash values is running.

    Hash Check Implementation (hash_helper.py)

    This file handles the creation and verification of hashes.

    def create_hash(content : bytes) -> str:
        return format(zlib.crc32(content), '08x')
    
    def validate_hash(validate_path : str) -> bool:
        hash_path = get_hash_path(validate_path)
    
        if is_file(hash_path):
            with open(hash_path) as hash_file:
                hash_content = hash_file.read()
    
            with open(validate_path, 'rb') as validate_file:
                validate_content = validate_file.read()
    
            return create_hash(validate_content) == hash_content
        return False
    

    Furthermore, download.py strictly checks if the values have changed from the time they were pulled.

    def validate_source_paths(source_paths : List[str]) -> Tuple[List[str], List[str]]:
        valid_source_paths = []
        invalid_source_paths = []
    
        for source_path in source_paths:
            if validate_hash(source_path):
                valid_source_paths.append(source_path)
            else:
                invalid_source_paths.append(source_path)
    
        return valid_source_paths, invalid_source_paths
    

    The Logic to Circumvent the Filter

    These checks are called in core.py as a pre-check during execution.

    def common_pre_check() -> bool:
        common_modules =\
        [
            content_analyser,
            face_classifier,
            face_detector,
            face_landmarker,
            face_masker,
            face_recognizer,
            voice_extractor
        ]
    
        content_analyser_content = inspect.getsource(content_analyser).encode()
        content_analyser_hash = hash_helper.create_hash(content_analyser_content)
    
        return all(module.pre_check() for module in common_modules) and content_analyser_hash == '803b5ec7'
    

    Unless the hash value matches '803b5ec7', the program won't run. Therefore, you must disable the check itself to bypass it.

    Bypass Code

    Rewrite the hash check portion within the common_pre_check function as follows:

    def common_pre_check() -> bool:
        common_modules =\
        [
            content_analyser,
            face_classifier,
            face_detector,
            face_landmarker,
            face_masker,
            face_recognizer,
            voice_extractor
        ]
    
        content_analyser_content = inspect.getsource(content_analyser).encode()
        content_analyser_hash = hash_helper.create_hash(content_analyser_content)
    
        return all(module.pre_check() for module in common_modules)  # Hash check disabled
    

    This skips the integrity check, allowing the program to run even if you've modified the NSFW filter logic.

    In Conclusion

    As you can see, while these measures are easily bypassed by someone who "understands program structure," they present a very high hurdle for "button-pushers" who just want to install and run. A two-tier defense using hash checks actually acts as a significant deterrent in practice.

    When you distribute a tool as source code, preventing tampering 100% is impossible. Don't forget that if you have "logic that absolutely must not be tampered with," the best choice is often not to publish the source code at all.

    See you in the next article! ♡

    Airi

    Airi

    Tokyo | 27F | Contractor Hobbies: Dancing (on hiatus) & Gaming Startup hopper Note: Email for business or just when the mood strikes.

    Related Articles

    • Fully Local! How to Build an Auto-Captioning Tool for Image Datasets Using Qwen 3.5
      Fully Local! How to Build an Auto-Captioning Tool for Image Datasets Using Qwen 3.5 3/22/2026
    • Mastering the Ollama API: Custom History & VRAM Management Without Official Libraries
      Mastering the Ollama API: Custom History & VRAM Management Without Official Libraries 3/19/2026
    • Streamlining Dataset Creation with YOLOv26
      Streamlining Dataset Creation with YOLOv26 3/17/2026

    Latest Articles

    • Fully Local! How to Build an Auto-Captioning Tool for Image Datasets Using Qwen 3.5
      Fully Local! How to Build an Auto-Captioning Tool for Image Datasets Using Qwen 3.5 3/22/2026
    • Mastering the Ollama API: Custom History & VRAM Management Without Official Libraries
      Mastering the Ollama API: Custom History & VRAM Management Without Official Libraries 3/19/2026
    • Streamlining Dataset Creation with YOLOv26
      Streamlining Dataset Creation with YOLOv26 3/17/2026
    Overclocking Time's

    A tech blog by a 20-something Japanese female startup contractor and "struggling" engineer!

    Navigation

    Home Blog Privacy Policy

    Connect

    Contact

    © 2026 Overclocking Time's. All rights reserved.