Hunting Bot Networks

Noam Rotem and Yuval Adam

Bots / Avatars / Sockpuppets


  • Crowd-source suspicious accounts
  • Identify suspicious clusters
  • Manual and automated research

Recap - The Turkish Network


Suspicious Metadata

Cultural Inaccuracies

False Flag

Suspicious Cluster

Organic Network

Media References


The Turkish Connection


  • Twitter disclosure
  • 142 accounts suspended

Kingdom Salvation

כנסיית האל הכל יכול

Israeli Girls Network

Israeli Girls Network

  • Same naming patterns
  • All accounts created within 4 hours
  • Still active...

Journalists at Risk

Fake News Campaign

Fake News Campaign

One-time Account

  • Old account
  • Wiped history clean
  • Re-branded as a "legit" account
  • Target journalists with DMs and @s

Social Graph Mismatch

Tech Infrasctructure

Twitter Data Collection

  • Python
  • PostgreSQL
  • SQLAlchemy
  • Celery


  • Twitter API calls
  • Response serialization and storage
  • Tagging (for research)
  • CSV and XLS exports
  • Web-based dashboard
  • Gephi for graph visualization

מודל לדוגמה

class User(Base):
    __tablename__ = 'users'

    id = Column(String(20), primary_key=True)
    name = Column(String(15), nullable=False)
    full_name = Column(Text)
    description = Column(Text)
    created = Column(DateTime)
    location = Column(Text)
    protected = Column(Boolean)

    followers_count = Column(Integer)
    friends_count = Column(Integer)
    favourites_count = Column(Integer)
    statuses_count = Column(Integer)
    listed_count = Column(Integer)

    imported = Column(DateTime(timezone=True),
    updated = Column(DateTime(timezone=True),

    tags = Column(ARRAY(Text), nullable=False,
        default=cast(array([], type_=Text), ARRAY(Text)))

    followers = relationship('User', secondary=follows,
        primaryjoin=id == follows.c.to_id,
        secondaryjoin=id == follows.c.from_id,,
        backref='friends', lazy='subquery')

    tweets = relationship('Tweet',
        primaryjoin=' == foreign(Tweet.user_id)',
        backref='user', lazy='subquery', viewonly=True)

    __table_args__ = (
        Index('ix_user_name_lower', func.lower('name')),
        Index('ix_user_tags', tags, postgresql_using='gin'),

Project Side-Quest



Data Collection

  • Browser fingerprinting
  • WebRTC de-anonymization
  • IP leakage

Next Steps

  • Crowd-funding campaign
  • Continue data collection and analysis


Twitter Dev Conf Eng

By Yuval Adam

Twitter Dev Conf Eng

  • 597
Loading comments...

More from Yuval Adam