Repository: discordjs/discord.js
File: packages/discord.js/src/structures/Message.js (JavaScript)

Code before:
   * channel.bulkDelete(messages.filter(message => message.bulkDeletable));
   */
  get bulkDeletable() {
    return (
      (this.inGuild() &&
        Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&
        this.deletable &&
        this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageMessages, false)) ??
      false
    );
  }

  /**
   * Whether the message is pinnable by the client user
   *
   * @type {boolean}
   * @readonly
   */
  get pinnable() {
    const { channel } = this;

    if (this.system) return false;
    if (!this.guild) return true;
    if (VoiceBasedChannelTypes.includes(channel?.type) || !channel?.viewable) return false;

    const permissions = channel?.permissionsFor(this.client.user);
    if (!permissions) return false;

    return permissions.has(PermissionFlagsBits.ReadMessageHistory | PermissionFlagsBits.PinMessages);
  }

  /**
   * Fetches the Message this crosspost/reply/pin-add references, if available to the client
   *
   * @returns {Promise<Message>}
   */
  async fetchReference() {
    if (!this.reference) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
    const { channelId, messageId } = this.reference;
    if (!messageId) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
    const channel = this.client.channels.resolve(channelId);
    if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
    return channel.messages.fetch(messageId);
  }

  /**
   * Whether the message is crosspostable by the client user
   *
   * @type {boolean}
   * @readonly
   */

Review comment (security):
To reach this point, it must be a voice-based channel that is viewable.

```suggestion
    const permissions = channel.permissionsFor(this.client.user);
```

Code after:
        Date.now() - this.createdTimestamp < MaxBulkDeletableMessageAge &&
        this.deletable &&
        this.channel?.permissionsFor(this.client.user).has(PermissionFlagsBits.ManageMessages, false)) ??
      false
    );
  }

  /**
   * Whether the message is pinnable by the client user
   *
   * @type {boolean}
   * @readonly
   */
  get pinnable() {
    const { channel } = this;

    if (this.system) return false;
    if (!this.guild) return true;
    if (!channel || channel.isVoiceBased() || !channel.viewable) return false;

    const permissions = channel.permissionsFor(this.client.user);
    if (!permissions) return false;

    return permissions.has(PermissionFlagsBits.ReadMessageHistory | PermissionFlagsBits.PinMessages);
  }

  /**
   * Fetches the Message this crosspost/reply/pin-add references, if available to the client
   *
   * @returns {Promise<Message>}
   */
  async fetchReference() {
    if (!this.reference) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
    const { channelId, messageId } = this.reference;
    if (!messageId) throw new DiscordjsError(ErrorCodes.MessageReferenceMissing);
    const channel = this.client.channels.resolve(channelId);
    if (!channel) throw new DiscordjsError(ErrorCodes.GuildChannelResolve);
    return channel.messages.fetch(messageId);
  }

  /**
   * Whether the message is crosspostable by the client user
   *
   * @type {boolean}
   * @readonly
   */
  get crosspostable() {
    const bitfield =
      PermissionFlagsBits.SendMessages |
      (this.author.id === this.client.user.id ? PermissionsBitField.DefaultBit : PermissionFlagsBits.ManageMessages);
    const { channel } = this;