Zum Hauptinhalt springen
tsecurity.de LIVE
Echtzeit-Radar & Feeds
Alle RSS Feeds
👥 Community & Social
Sicherheitslücken (CVE)CVE-2026-81554 | IBM DataStage 5.4.0.0 path traversal(19.09.2026 um 06:42 Uhr)
Sicherheitslücken (CVE)CVE-2026-19542 | GNU glibc tdelete memory corruption (WID-SEC-2026-3014)(19.09.2026 um 07:01 Uhr)
Sicherheitslücken (CVE)CVE-2026-81554 | IBM DataStage 5.4.0.0 path traversal(19.09.2026 um 06:42 Uhr)
Sicherheitslücken (CVE)CVE-2026-19542 | GNU glibc tdelete memory corruption (WID-SEC-2026-3014)(19.09.2026 um 07:01 Uhr)
Intelligence View
⚡ tsecurity.de Intelligence

Why "must be subscribed to enter" is a checkbox I had to delete from a YouTube giveaway picker

A YouTuber I know asked me to help pick a winner from a giveaway video fairly, because doing it by scrolling through comments and eyeballing one invites exactly the kind of "the mod's friend won" accusations you'd expect. I figured: grab the comments, roll a die, done — how hard can that be? Turns out, once you actually build it against the real YouTube Data API v3 instead of imagining how it probably works, there's pagination to chase, replies to exclude, duplicate commenters to catch, and one feature I had to rip out because it's technically impossible to build honestly.

Turning whatever URL someone pastes into a video ID

People paste video links in three different shapes — the desktop watch?v= link, the shortened youtu.be/ link, and the shorts/ link — and none of them go through a real URL parser, just string splitting on whichever marker is present:

let searchID = "";
if (searchKey.value.indexOf("v=") > -1) {
  searchID = searchKey.value.split("v=")[1];
} else if (searchKey.value.indexOf("youtu.be") > -1) {
  // https://youtu.be/KtkW3Hx0MvA
  searchID = searchKey.value.split("youtu.be/")[1];
} else if (searchKey.value.indexOf("shorts") > -1) {
  // https://www.youtube.com/shorts/QWUTKpZmSX0
  searchID = searchKey.value.split("shorts/")[1];
}

This works for a clean link, but it doesn't strip anything that comes after the ID. Paste a link with a timestamp (&t=45s) or a share-tracking suffix (?si=xyz) and that junk rides along as part of searchID, gets sent straight to the video-lookup call, and comes back as a generic "couldn't find that video" error — which is technically true but tells the organizer nothing about why. I didn't catch this until someone pasted a link straight from the YouTube mobile app's share sheet, which appends a tracking param by default.

Paginating through the comments API without losing your place

YouTube's commentThreads endpoint hands back comments in pages of up to 100, with a nextPageToken when there's more. The fetch function just calls itself with that token until there isn't one:

const getComment = (searchID, pageToken = null) => {
  isLoading.value = true;
  $API.youtubeData.youtube_getComment(searchID, pageToken).then((res) => {
    let { data } = res;
    if (data && data.items) {
      data.items.forEach((item) => {
        comentData.push({
          authorChannelId: item.snippet.topLevelComment.snippet.authorChannelId,
          authorDisplayName: item.snippet.topLevelComment.snippet.authorDisplayName,
          likeCount: item.snippet.topLevelComment.snippet.likeCount,
          textOriginal: item.snippet.topLevelComment.snippet.textOriginal,
          totalReplyCount: item.snippet.totalReplyCount,
          // ...a few more fields for the table
        });
      });
      if (data.nextPageToken) {
        getComment(searchID, data.nextPageToken);
      } else {
        isLoading.value = false;
      }
    }
  });
};

Notice everything is pulled from topLevelComment.snippet — never the replies themselves. totalReplyCount is captured just so it can be displayed in the table, but the actual reply text is never fetched. So if a giveaway's rule is "reply to the pinned comment to enter" rather than "leave a top-level comment," this tool structurally can't see those entries — it only ever eats top-level comments, which is also why the UI explicitly labels its count as "comments (excluding replies)."

One entry per commenter, not per comment

Before picking a winner, every comment runs through a filter chain, and the interesting one is duplicate removal:

const MessageFrom = new Set();
let filterList = comentData.filter(({ textDisplay, likeCount, authorChannelId, publishedAt }) => {
  if (mustContain.value && textDisplay.indexOf(mustContainValue.value) == -1) return false;
  if (mustLength.value && textDisplay.length < mustLengthValue.value) return false;
  if (mustLike.value && likeCount * 1 < mustLikeValue.value) return false;

  if (mustNoRepeat.value) {
    if (MessageFrom.has(authorChannelId)) {
      return false;
    } else {
      MessageFrom.add(authorChannelId);
    }
  }
  // ...date-range check
  return true;
});

Dedup is keyed on authorChannelId, not the display name — a name is just cosmetic text a user can change at any moment, so two comments from the same account could show two different names. The channel ID is the one thing that's actually stable. Since Array.filter walks the list in order, whichever comment from a given channel appears first is the one that survives; any later comment from that same account is silently dropped, keyword-spam or not.

The date-range check on the next line is the one piece of this function I'd flag if I were reviewing someone else's PR:

if (
  (mustDate.value &&
    new Date(new Date(mustDateStart.value).toDateString()).getTime() >
      new Date(publishedAt).getTime()) ||
  new Date(new Date(mustDateEnd.value).toDateString()).getTime() + 86400000 <
    new Date(publishedAt).getTime()
)
  return false;

The parentheses only wrap mustDate.value && startCheck — the end-date half of the || has no such guard, so it's evaluated regardless of whether the "date range" checkbox is even ticked. In practice it's harmless today only because an empty mustDateEnd produces Invalid Date, and NaN < anything is always false. But it's one stray value away from silently filtering out legitimate entries the moment someone fills in an end date without checking the box first.

Picking winners without replacement, the brute-force way

Once the pool is filtered, picking N winners isn't a shuffle — it's rejection sampling:

let real_index = [];
for (let i = 0; i < AwardNumber.value; i++) {
  let now = random(filterList.length);
  if (!real_index.includes(now)) {
    real_index.push(now);
  } else {
    i--; // collision — roll again
  }
}

function random(real_max) {
  return Math.floor(Math.random() * (real_max - 0)) + 0;
}

Roll a random index; if it's already been picked, back the loop counter up and roll again. It's not a proper Fisher–Yates partial shuffle, and it doesn't need to be — the code already checked earlier that filterList.length >= AwardNumber.value, so the loop is guaranteed to eventually land on N distinct indexes, and for a typical giveaway (a handful of winners out of hundreds of eligible comments) collisions are rare enough that a plain retry loop is simpler to read than a real shuffle and costs nothing anyone would notice.

Where this quietly falls short

There's a checkbox still sitting in the template, commented out, for "must be subscribed to the channel" — with a note next to it admitting that anyone who hasn't made their subscriptions public gets treated as unsubscribed. I left it disabled on purpose: YouTube's API has no endpoint that tells you "does channel A have viewer B subscribed," because a user's subscription list is private by default and there's no way to check it from public comment data without that specific user handing over their own OAuth token. Any tool claiming to enforce a subscribe-to-enter rule automatically is either lying or quietly excluding most of your actual subscribers.

A couple other honest gotchas: the comments API has a daily quota, so a video with an unusually large comment count can exhaust it mid-fetch and just stop with a generic error. And dedup by channel ID stops someone from commenting five times on one account, but does nothing to stop someone running the exact same giveaway comment from two separate Google accounts — there's no way to detect that from a comment thread alone.

I cleaned this up into a small free tool if you run YouTube giveaways and want to skip building your own version: YouTube Comment Picker Tool. No sign-up, just paste a video link.

Available in other languages

Zum Aktualisieren ziehen
ZERO-DAY CVE-2026-61591 | djust provides Phoenix LiveView-style reactive server-side rendering for…
Advisory →
TTS Reader • tsecurity.de Voice
tsecurity.de Icon
tsecurity.de App
Offline-Lesen, Eilmeldungen & 0ms Ladezeit

Installiere tsecurity.de direkt auf deinen Home-Bildschirm für das ultimative Vollbild-Magazinerlebnis ohne Browser-Leisten.

Nächster Beitrag
Themen-Radar & Intelligence Matrix
Echtzeit-Taxonomie nach Angriffsvektoren & Plattformen

tsecurity.de Live Threat Radar

🔴 LIVE RADAR
MONITORING
AKTIV
CVE-DATENBANK
LIVE
🔍
Radar › Alle Kategorien
Alle aus Alle Kategorien 2.659.583
Community Radar & Live Chat
Sentinel Bot online • Live-Stream
Dein Cluster: Security Explorer
Match:
lädt…
Verbindung zum Community-Stream wird aufgebaut...
Bearbeitungsmodus — Senden überschreibt deine Nachricht
Community-Puls — was gerade passiert
lädt…
Aktivitäten deiner Analysten
lädt…
Neues Thema oder Eilmeldung einreichen

Reiche interessante Links, Zero-Days oder Debatten ein. Die Community entscheidet per Upvote über die Veröffentlichung.

Heiß diskutierte Einreichungen
🔖 Gespeicherte Artikel
📂 Keine gespeicherten Artikel vorhanden.
Rechts: Artikel Ziehen Links: RSS
Hoch: nächster Artikel Runter: zurück / schließen
News NIS-2 Frühwarnung Tier-1 Intel ⏱️ 3 Min vor 10 Min
Artikeldaten werden geladen...

Rechts: Original Links: RSS-Ansicht
↗ Original-Quelle
Social Reaktionen Stimme abgeben (+5 Karma)
Einstufung & Relevanz-Poll 0 Stimmen
In sozialen Netzwerken teilen 1-Klick