system: You are an expert security code reviewer. You will be shown a source code file along with a multi-select question listing several CWE (Common Weakness Enumeration) categories. Your task is to identify which of the listed CWEs are present in the code.

OUTPUT FORMAT: Respond with the letter(s) of all correct options, sorted alphabetically and comma-separated, wrapped in a single \boxed{...}. Examples: `\boxed{A}` for one correct, `\boxed{A,C}` for two, `\boxed{A,C,E}` for three. Output the boxed answer ONLY -- no explanation, no other text.

user: ```python
import time
from hashlib import md5

import requests
from django.conf import settings
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST
from rest_framework.views import APIView
from rest_framework_extensions.cache.decorators import cache_response

from sputniktask.apps.accounts.authentication import ExpiringTokenAuthentication
from sputniktask.apps.marvel.serializers import ComicsListSerializer, OffsetPaginationSerializer


class MarvelAPIMixIn(APIView):
    authentication_classes = (ExpiringTokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    api_method = None
    default_params = None

    serializer_class = OffsetPaginationSerializer

    @staticmethod
    def get_signature():
        ts = str(time.time())
        return {
            'ts': ts,
            'hash': md5(ts + settings.MARVEL_SECRET_KEY + settings.MARVEL_PUBLIC_KEY).hexdigest(),
            'apikey': settings.MARVEL_PUBLIC_KEY,
        }

    def call_api(self, method, params):
        query_params = dict(params, **self.get_signature())
        return requests.get(settings.MARVEL_API_URL + method, params=query_params)


class ComicsListWithTitle(MarvelAPIMixIn):
    """
    Get the list of comics with specific title.

    Response object and errors is described at
    [developer.marvel.com](http://developer.marvel.com/docs#!/public/getComicsCollection_get_6)
    """

    api_method = 'comics'
    default_params = {
        'format': 'comic',
        'formatType': 'comic',
        'orderBy': 'focDate',
        'limit': 10,
        'offset': 0,
    }

    serializer_class = ComicsListSerializer

    @cache_response()
    def get(self, request, *args, **kwargs):
        """
        ---
        parameters:
            - name: title
              description: Required parameter.
              required: true
              type: string
              paramType: query
            - name: limit
              description: 	Limit the result set to the specified number of resources.
              required: false
              type: int
              paramType: query
            - name: offset
              description: Skip the specified number of resources in the result set.
              required: false
              type: int
              paramType: query
        """
        serializer = self.serializer_class(data=request.query_params)
        if serializer.is_valid():
            params = self.default_params.copy()
            params.update(**serializer.data)
            response = self.call_api(self.api_method, params)
            return Response(response.json(), status=response.status_code)
        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)


class HeroEventsList(MarvelAPIMixIn):
    """
    Get the list of events which related to the provided character.

    Response object and errors is described at
    [developer.marvel.com](http://developer.marvel.com/docs#!/public/getEventsCollection_get_18)
    """

    api_method = 'events'
    default_params = {
        'characters': None,
        'limit': 10,
        'offset': 0
    }

    @cache_response()
    def get(self, request, *args, **kwargs):
        """
        ---
        parameters:
            - name: limit
              description: 	Limit the result set to the specified number of resources.
              required: false
              type: int
              paramType: query
            - name: offset
              description: Skip the specified number of resources in the result set.
              required: false
              type: int
              paramType: query
        """
        serializer = self.serializer_class(data=request.query_params)
        if serializer.is_valid():
            params = self.default_params.copy()
            params.update(characters=kwargs['hero_id'], **serializer.data)
            response = self.call_api(self.api_method, params)
            return Response(response.json(), status=response.status_code)
        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)


class ComicsListWithSimilarAuthors(MarvelAPIMixIn):
    """
    Get the list of comics which have similar creators as a provided one.

    Response object and errors is described at
    [developer.marvel.com](http://developer.marvel.com/docs#!/public/getComicsCollection_get_6)
    """

    api_method = 'comics'
    default_params = {
        'creators': '',
        'format': 'comic',
        'formatType': 'comic',
        'orderBy': 'focDate',
        'limit': 10,
        'offset': 0
    }

    @cache_response()
    def get(self, request, *args, **kwargs):
        """
        ---
        parameters:
            - name: limit
              description: 	Limit the result set to the specified number of resources.
              required: false
              type: int
              paramType: query
            - name: offset
              description: Skip the specified number of resources in the result set.
              required: false
              type: int
              paramType: query
        """
        serializer = self.serializer_class(data=request.query_params)
        if serializer.is_valid():
            response = self.call_api('comics/{}/creators'.format(kwargs['comic_id']), {'limit': 100})
            if response.status_code == 200:
                authors_list = [str(item['id']) for item in response.json()['data']['results']]
                if authors_list:
                    params = self.default_params.copy()
                    creators = '.'.join(authors_list)
                    params.update(creators=creators, **serializer.data)
                    response = self.call_api(self.api_method, params)
                else:
                    return Response({'detail': 'Seems like there is no such comic in Marvel database.'},
                                    status=HTTP_400_BAD_REQUEST)
            return Response(response.json(), status=response.status_code)
        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)


class ComicsListWithSimilarCharacters(MarvelAPIMixIn):
    """
    Get the list of comics which have similar characters as a provided one.

    Response object and errors is described at
    [developer.marvel.com](http://developer.marvel.com/docs#!/public/getComicsCollection_get_6)
    """

    api_method = 'comics'
    default_params = {
        'characters': '',
        'format': 'comic',
        'formatType': 'comic',
        'orderBy': 'focDate',
        'limit': 10,
        'offset': 0
    }

    @cache_response()
    def get(self, request, *args, **kwargs):
        """
        ---
        parameters:
            - name: limit
              description: 	Limit the result set to the specified number of resources.
              required: false
              type: int
              paramType: query
            - name: offset
              description: Skip the specified number of resources in the result set.
              required: false
              type: int
              paramType: query
        """
        serializer = self.serializer_class(data=request.query_params)
        if serializer.is_valid():
            response = self.call_api('comics/{}/characters'.format(kwargs['comic_id']), {'limit': 100})
            if response.status_code == 200:
                hero_list = [str(item['id']) for item in response.json()['data']['results']]
                if hero_list:
                    params = self.default_params.copy()
                    characters = '.'.join(hero_list)
                    params.update(characters=characters, **serializer.data)
                    response = self.call_api(self.api_method, params)
                else:
                    return Response({'detail': 'Seems like there is no such comic in Marvel database.'},
                                    status=HTTP_400_BAD_REQUEST)
            return Response(response.json(), status=response.status_code)
        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)


class ComicsListFromSameSeries(MarvelAPIMixIn):
    """
    Get the list of comics from the same series as a provided one.

    Response object and errors is described at
    [developer.marvel.com](http://developer.marvel.com/docs#!/public/getComicsCollection_get_6)
    """

    api_method = 'comics'
    default_params = {
        'series': '',
        'format': 'comic',
        'formatType': 'comic',
        'orderBy': 'focDate',
        'limit': 10,
        'offset': 0
    }

    @cache_response()
    def get(self, request, *args, **kwargs):
        """
        ---
        parameters:
            - name: limit
              description: 	Limit the result set to the specified number of resources.
              required: false
              type: int
              paramType: query
            - name: offset
              description: Skip the specified number of resources in the result set.
              required: false
              type: int
              paramType: query
        """
        serializer = self.serializer_class(data=request.query_params)
        if serializer.is_valid():
            response = self.call_api('series', {'limit': 1,
                                                'comics': kwargs['comic_id']})
            if response.status_code == 200:
                series_list = [str(item['id']) for item in response.json()['data']['results']]
                if series_list:
                    params = self.default_params.copy()
                    series = series_list[0]
                    params.update(series=series, **serializer.data)
                    response = self.call_api(self.api_method, params)
                else:
                    return Response({'detail': 'Seems like there is no such comic in Marvel database.'},
                                    status=HTTP_400_BAD_REQUEST)
            return Response(response.json(), status=response.status_code)
        return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

```

Which of the following CWE vulnerability categories are present in this code? Multiple options may be correct.

  A) CWE-327: Use of a Broken or Risky Cryptographic Algorithm
  B) CWE-200: Exposure of Sensitive Information to an Unauthorized Actor
  C) CWE-116: Improper Encoding or Escaping of Output
  D) CWE-776: Improper Restriction of Recursive Entity References in DTDs ('XML Entity Expansion')
  E) CWE-312: Cleartext Storage of Sensitive Information
  F) CWE-918: Server-Side Request Forgery (SSRF)
Answer: A,F