Rahul Bhotika

47 papers A* 9A 2B 4Journal 14Unranked 18
YearRankTypeTitle / Venue / Authors
2025 conf
NAACL (Long Papers)
Abhijnan Nath, Andrey Volozin, Saumajit Saha, Albert Nanda, Galina Grunin, Rahul Bhotika, Nikhil Krishnaswamy
2023 A* conf
ICLR
Gukyeong Kwon, Zhaowei Cai, Avinash Ravichandran, Erhan Bas, Rahul Bhotika, Stefano Soatto
2023 A conf
WACV
Zudi Lin, Erhan Bas, Kunwar Yashraj Singh, Gurumurthy Swaminathan, Rahul Bhotika
2022 A* conf
CVPR
Tz-Ying Wu, Gurumurthy Swaminathan, Zhizhong Li, Avinash Ravichandran, Nuno Vasconcelos, Rahul Bhotika, Stefano Soatto
2022 J jnl
CoRR
Tz-Ying Wu, Gurumurthy Swaminathan, Zhizhong Li, Avinash Ravichandran, Nuno Vasconcelos, Rahul Bhotika, Stefano Soatto
2022 J jnl
CoRR
Gukyeong Kwon, Zhaowei Cai, Avinash Ravichandran, Erhan Bas, Rahul Bhotika, Stefano Soatto
2022 A* conf
NeurIPS
Zhaowei Cai, Avinash Ravichandran, Paolo Favaro, Manchen Wang, Davide Modolo, Rahul Bhotika, Zhuowen Tu, Stefano Soatto
2022 J jnl
CoRR
Zhaowei Cai, Avinash Ravichandran, Paolo Favaro, Manchen Wang, Davide Modolo, Rahul Bhotika, Zhuowen Tu, Stefano Soatto
2022 A* conf
CVPR
Matthew Wallingford, Hao Li, Alessandro Achille, Avinash Ravichandran, Charless C. Fowlkes, Rahul Bhotika, Stefano Soatto
2022 J jnl
CoRR
Matthew Wallingford, Hao Li, Alessandro Achille, Avinash Ravichandran, Charless C. Fowlkes, Rahul Bhotika, Stefano Soatto
2022 conf
ECCV (36)
Zhaowei Cai, Gukyeong Kwon, Avinash Ravichandran, Erhan Bas, Zhuowen Tu, Rahul Bhotika, Stefano Soatto
2022 J jnl
CoRR
Zhaowei Cai, Gukyeong Kwon, Avinash Ravichandran, Erhan Bas, Zhuowen Tu, Rahul Bhotika, Stefano Soatto
2021 J jnl
CoRR
Aditya Deshpande, Alessandro Achille, Avinash Ravichandran, Hao Li, Luca Zancato, Charless C. Fowlkes, Rahul Bhotika, Stefano Soatto, Pietro Perona
2021 A* conf
ICCV
Sagnik Das, Kunwar Yashraj Singh, Jon Wu, Erhan Bas, Vijay Mahadevan, Rahul Bhotika, Dimitris Samaras
2021 A* conf
ICLR
Hrayr Harutyunyan, Alessandro Achille, Giovanni Paolini, Orchid Majumder, Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2021 J jnl
CoRR
Hrayr Harutyunyan, Alessandro Achille, Giovanni Paolini, Orchid Majumder, Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2021 J jnl
CoRR
Zhizhong Li, Avinash Ravichandran, Charless C. Fowlkes, Marzia Polito, Rahul Bhotika, Stefano Soatto
2021 J jnl
CoRR
Orchid Majumder, Avinash Ravichandran, Subhransu Maji, Marzia Polito, Rahul Bhotika, Stefano Soatto
2020 J jnl
CoRR
Xialei Liu, Hao Yang, Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2020 conf
ECCV (7)
Qing Liu, Orchid Majumder, Alessandro Achille, Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2020 J jnl
CoRR
Qing Liu, Orchid Majumder, Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2020 A* conf
NeurIPS
Luca Zancato, Alessandro Achille, Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2020 J jnl
CoRR
Luca Zancato, Alessandro Achille, Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2020 A* conf
ICLR
Hao Li, Pratik Chaudhari, Hao Yang, Michael Lam, Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2020 J jnl
CoRR
Hao Li, Pratik Chaudhari, Hao Yang, Michael Lam, Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2019 A* conf
ICCV
Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2019 J jnl
CoRR
Avinash Ravichandran, Rahul Bhotika, Stefano Soatto
2015 B conf
Image Processing
Dirk Ryan Padfield, Rahul Bhotika, Alexander Natanzon
2012 B conf
Image Processing
Xiaoxing Li, Paulo R. S. Mendonça, Rahul Bhotika
2011 conf
ISBI
Fei Zhao, Rahul Bhotika
2011 conf
ISBI
Paulo R. S. Mendonça, Peter Lamb, Evren Asma, Ravindra M. Manjeshwar, Osama R. Mawlawi, Rahul Bhotika
2011 B conf
Image Processing
Mark Joshi, Paulo R. S. Mendonça, Darin Okerlund, Peter Lamb, Naveen Kulkarni, Duque de Pinho, Dushyant Sahani, Rahul Bhotika
2011 B conf
Image Processing
András Kriston, Paulo R. S. Mendonça, Alvin C. Silva, Robert G. Paden, William Pavlicek, Dushyant Sahani, Benedek Janos Kis, László Ruskó, Darin Okerlund, Rahul Bhotika
2011 conf
HISB
Xiaofeng Liu, Qi Song, Paulo R. S. Mendonça, Xiaodong Tao, Rahul Bhotika
2010 conf
ISBI
Fei Zhao, Rahul Bhotika, Paulo R. S. Mendonça, Nils Krahnstoever, James V. Miller
2010 conf
Computer-Aided Diagnosis
Alberto Santamaría-Pang, Sandeep Dutta, Sokratis Makrogiannis, Amy K. Hara, William Pavlicek, Alvin C. Silva, Brian Thomsen, Scott Robertson, Darin Okerlund, David A. Langan, Rahul Bhotika
2010 conf
ISBI
Mahnaz Maddah, Paulo R. S. Mendonça, Rahul Bhotika
2009 conf
MICCAI (1)
Sokratis Makrogiannis, Rahul Bhotika, James V. Miller, John Skinner, Melissa Vass
2007 conf
MICCAI (2)
John Melonakos, Paulo R. S. Mendonça, Rahul Bhotika, Saad A. Sirohey
2007 conf
IPMI
Paulo R. S. Mendonça, Rahul Bhotika, Fei Zhao, James V. Miller
2007 conf
ISBI
Fei Zhao, Paulo R. S. Mendonça, Rahul Bhotika, James V. Miller
2006 conf
ICPR (1)
Michael T. Chan, Anthony Hoogs, Zhaohui Sun, John Schmiederer, Rahul Bhotika, Gianfranco Doretto
2006 conf
CVPR (2)
Michael T. Chan, Anthony Hoogs, Rahul Bhotika, A. G. Amitha Perera, John Schmiederer, Gianfranco Doretto
2006 conf
MICCAI (2)
Rahul Bhotika, Paulo R. S. Mendonça, Saad A. Sirohey, Wesley D. Turner, Ying-Lin Lee, Julie M. McCoy, Rebecca E. B. Brown, James V. Miller
2005 A conf
MICCAI
Paulo R. S. Mendonça, Rahul Bhotika, Saad A. Sirohey, Wesley D. Turner, James V. Miller, Ricardo S. Avila
2002 conf
ECCV (3)
Rahul Bhotika, David J. Fleet, Kiriakos N. Kutulakos
2001 conf
CVPR (1)
Matthew Brand, Rahul Bhotika
redb/extractors/malcontent.py
← Index redb/extractors/malcontent.py python
import inspect
import json
import subprocess
from typing import Any
from datetime import datetime, timezone

from redb.extractors.enum import Tag
from redb.models.dataclasses import Malcontent
from redb.extractors.extractor import Extractor
from dotenv import load_dotenv
import os

load_dotenv(override=True)


class MalcontentExtractor(Extractor):
    """
    Extractor for malcontent tool from chainguard-dev/malcontent.

    Malcontent discovers supply-chain compromises through context, differential
    analysis, and 14,000+ YARA rules. It analyzes binaries and code to detect
    malicious content and suspicious behavioral patterns.

    Binary can be extracted from Docker image:
        docker cp $(docker create cgr.dev/chainguard/malcontent:latest):/usr/bin/mal /usr/local/bin/mal

    Stores full JSON output for materialized view extraction.
    """

    # Cache version at class level to avoid repeated subprocess calls
    _cached_version = None

    def __init__(
        self,
        filepath,
        log,
        exporters=None,
        index_prefix=None,
        elastic_index=None,
        known_benign=False,
        known_malicious=False,
    ):
        super().__init__(
            filepath,
            log,
            exporters,
            index_prefix,
            elastic_index,
            known_benign,
            known_malicious
        )
        self.malcontent = None

    @classmethod
    def _get_malcontent_version(cls, log) -> str:
        """Get malcontent version, cached at class level."""
        if cls._cached_version is not None:
            return cls._cached_version

        malcontent_path = os.getenv("MALCONTENT_PATH", "/usr/local/bin/mal")
        try:
            result = subprocess.run(
                [malcontent_path, "--version"],
                capture_output=True,
                text=True,
                timeout=10
            )
            version_output = result.stdout.strip()
            if result.returncode == 0 and version_output:
                # Parse "malcontent version v1.21.5" -> "1.21.5"
                if version_output.startswith("malcontent version v"):
                    version_output = version_output[len("malcontent version v"):]
                elif version_output.startswith("malcontent version "):
                    version_output = version_output[len("malcontent version "):]
                cls._cached_version = version_output
            else:
                cls._cached_version = "unknown"
        except Exception as e:
            log.warning(f"Could not get malcontent version: {e}")
            cls._cached_version = "unknown"

        return cls._cached_version

    def _extract_malcontent(self):
        self.log.debug(inspect.currentframe().f_code.co_name)
        TIMEOUT = int(os.getenv("MALCONTENT_TIMEOUT", "300"))
        malcontent_path = os.getenv("MALCONTENT_PATH", "/usr/local/bin/mal")

        malcontent_command = [malcontent_path, "analyze", "--format=json", self.filepath]

        import signal

        try:
            process = subprocess.Popen(
                malcontent_command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                text=True,
                preexec_fn=os.setsid
            )

            try:
                stdout, stderr = process.communicate(timeout=TIMEOUT)
                if process.returncode != 0:
                    self.log.error(f"Error running malcontent, return code: {process.returncode}, stderr: {stderr}")
                    return {}
            except subprocess.TimeoutExpired:
                self.log.warning(f"The malcontent command timed out after {TIMEOUT} seconds, terminating process group")
                try:
                    os.killpg(process.pid, signal.SIGTERM)
                    try:
                        process.wait(timeout=3)
                    except subprocess.TimeoutExpired:
                        self.log.warning("Process didn't terminate with SIGTERM, sending SIGKILL")
                        os.killpg(process.pid, signal.SIGKILL)
                    process.wait()
                except (ProcessLookupError, OSError) as e:
                    self.log.warning(f"Error while killing process: {e}")
                return {}

            try:
                malcontent_output = json.loads(stdout)
            except json.JSONDecodeError as e:
                self.log.error(f"Error parsing malcontent output: {e}")
                return {}

            # Unwrap the Files/<path> structure to get the inner content
            # Structure is: {"Files": {"/path/to/file": {<actual content>}}}
            files_dict = malcontent_output.get("Files", {})
            if not files_dict:
                self.log.warning("Malcontent output has no 'Files' key")
                return {}

            # Get the first (and only) file's content
            file_content = next(iter(files_dict.values()), {})
            if not file_content:
                self.log.warning("Malcontent output has empty file content")
                return {}

            # Extract risk score and level from the unwrapped content
            risk_score = file_content.get("RiskScore", 0)
            risk_level = file_content.get("RiskLevel", "")

            version = self._get_malcontent_version(self.log)

            self.malcontent = Malcontent(
                malcontent_dump=json.dumps(file_content),
                version=version,
                risk_score=risk_score,
                risk_level=risk_level
            )
            self.log.debug(f"Malcontent analysis complete, version={version}, risk={risk_level}({risk_score})")

        except Exception as e:
            self.log.error(f"Unexpected error in malcontent extraction: {str(e)}")
            if 'process' in locals() and process.poll() is None:
                try:
                    os.killpg(process.pid, signal.SIGKILL)
                    process.wait()
                except:
                    pass
            return {}

    def prepare_export_data(self, exporter_type: str) -> Any:
        if exporter_type == "ClickHouseExporter":
            current_time = datetime.now(timezone.utc)

            data = [[
                self.sha256,
                current_time,
                self.malcontent.version,
                self.malcontent.risk_score,
                self.malcontent.risk_level,
                self.malcontent.malcontent_dump
            ]]

            column_names = [
                'sha256', 'analysis_date',
                'malcontent_version', 'malcontent_risk_score', 'malcontent_risk_level',
                'malcontent_json'
            ]

            column_type_names = [
                'FixedString(64)',
                'DateTime64(3, \'UTC\')',
                'LowCardinality(String)', 'UInt8', 'LowCardinality(String)',
                'JSON'
            ]

            return (data, column_names, column_type_names)

    def get_clickhouse_table(self) -> str:
        return "redb_malcontent"

    def extract(self):
        self.log.debug(inspect.currentframe().f_code.co_name)
        try:
            self._extract_malcontent()
            return self.malcontent
        except Exception as e:
            self.log.error(f"Error extracting malcontent: {e}")
            return None

    def tag(self):
        return Tag.MALCONTENT.value